1/* @title: Code Fuzzing Injections */
2#pragma once
3#include <linker/symbols.h>
4#include <stdatomic.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_DEFINE(struct inject_site, inject_sites);
26
27/* Have to do this as it is not static */
28#define INJECT_SITE_ATTRIBUTE \
29 __attribute__((section(".kernel_inject_sites"), used))
30
31#define INJECT_SITE_DECLARE(id, injkind, description) \
32 INJECT_SITE_ATTRIBUTE struct inject_site __inject_site_##id = { \
33 .name = #id, .desc = (description), .kind = (injkind)}
34
35#define INJECT_SITE_DEFINE(id) extern struct inject_site __inject_site_##id
36#define INJECT_SITE(id) (&__inject_site_##id)
37
38static inline void inject_arm(struct inject_site *s, uint32_t seed,
39 uint32_t nth) {
40 atomic_store_explicit(&s->seed, seed, memory_order_relaxed);
41 atomic_store_explicit(&s->nth, nth, memory_order_relaxed);
42 atomic_store_explicit(&s->counter, 0, memory_order_relaxed);
43 atomic_store_explicit(&s->armed, true, memory_order_relaxed);
44}
45
46static inline void inject_disarm(struct inject_site *s) {
47 atomic_store_explicit(&s->armed, false, memory_order_relaxed);
48}
49
50#ifdef INJECT_ENABLED
51void inject_delay_impl(struct inject_site *s);
52bool inject_fail_impl(struct inject_site *s) __warn_unused_result;
53
54#define INJECT_DELAY(id) \
55 do { \
56 if (unlikely(atomic_load_explicit(&INJECT_SITE(id)->armed, \
57 memory_order_relaxed))) \
58 inject_delay_impl(INJECT_SITE(id)); \
59 } while (0)
60
61#define INJECT_FAIL(id) \
62 (unlikely(atomic_load_explicit(&INJECT_SITE(id)->armed, \
63 memory_order_relaxed)) && \
64 inject_fail_impl(INJECT_SITE(id)))
65#else
66#define INJECT_DELAY(id) ((void) 0)
67#define INJECT_FAIL(id) (false)
68#endif
69