1/* @title: Code Fuzzing Injections */
2#pragma once
3#include <atomic.h>
4#include <linker/symbols.h>
5#include <stdbool.h>
6#include <stddef.h>
7#include <stdint.h>
8
9enum inject_kind {
10 INJECT_KIND_DELAY = 1, /* spin */
11 INJECT_KIND_FAIL = 1 << 1, /* Force failures */
12};
13
14struct inject_site {
15 const char *name;
16 const char *desc;
17 enum inject_kind kind;
18
19 atomic_bool armed;
20 atomic_uint32_t seed;
21 atomic_uint32_t nth;
22 atomic_uint32_t counter;
23};
24
25LINKER_SECTION_EXTERN(struct inject_site, inject_sites);
26
27#define INJECT_SITE_ATTRIBUTE cc_section(".kernel_inject_sites") cc_used
28
29#define INJECT_SITE_DEFINE(id, injkind, description) \
30 INJECT_SITE_ATTRIBUTE struct inject_site __inject_site_##id = { \
31 .name = #id, .desc = (description), .kind = (injkind)}
32
33#define INJECT_SITE_EXTERN(id) extern struct inject_site __inject_site_##id
34#define INJECT_SITE(id) (&__inject_site_##id)
35
36static inline void inject_arm(struct inject_site *s, uint32_t seed,
37 uint32_t nth) {
38 atomic_store_rlx(&s->seed, seed);
39 atomic_store_rlx(&s->nth, nth);
40 atomic_store_rlx(&s->counter, 0);
41 atomic_store_rlx(&s->armed, true);
42}
43
44static inline void inject_disarm(struct inject_site *s) {
45 atomic_store_rlx(&s->armed, false);
46}
47
48#ifdef INJECT_ENABLED
49void inject_delay_impl(struct inject_site *s);
50cc_warn_unused_result bool inject_fail_impl(struct inject_site *s);
51
52#define INJECT_DELAY(id) \
53 do { \
54 if (cc_unlikely(atomic_load_rlx(&INJECT_SITE(id)->armed))) \
55 inject_delay_impl(INJECT_SITE(id)); \
56 } while (0)
57
58#define INJECT_FAIL(id) \
59 (cc_unlikely(atomic_load_rlx(&INJECT_SITE(id)->armed)) && \
60 inject_fail_impl(INJECT_SITE(id)))
61#else
62#define INJECT_DELAY(id) ((void) 0)
63#define INJECT_FAIL(id) (false)
64#endif
65