1 /* Copyright (c) 2022 Google, LLC.
2 * SPDX-License-Identifier: Apache-2.0
3 */
4 #include <zephyr/kernel.h>
5 #include <string.h>
6 #include <zephyr/irq.h>
7
8 /* Fuzz testing is coverage-based, so we want to hide a failure case
9 * (a write through a null pointer in this case) down inside a call
10 * tree in such a way that it would be very unlikely to be found by
11 * randomly-selected input. But the fuzzer can still find it in
12 * linear(-ish) time by discovering each new function along the way
13 * and then probing that new space. The 1 in 2^56 case here would
14 * require months-to-years of work for a large datacenter, but the
15 * fuzzer gets it in 20 seconds or so. This requires that the code for
16 * each case be distinguishable/instrumentable though, which is why we
17 * generate the recursive handler functions this way and disable
18 * inlining to prevent optimization.
19 */
20 int *global_null_ptr;
21 static const uint8_t key[] = { 0x9e, 0x21, 0x0c, 0x18, 0x9d, 0xd1, 0x7d };
22 bool found[ARRAY_SIZE(key)];
23
24 #define LASTKEY (ARRAY_SIZE(key) - 1)
25
26 #define GEN_CHECK(cur, nxt) \
27 void check##nxt(const uint8_t *data, size_t sz); \
28 void __attribute__((noinline)) check##cur(const uint8_t *data, size_t sz) \
29 { \
30 if (cur < sz && data[cur] == key[cur]) { \
31 if (!found[cur]) { \
32 printk("#\n# Found key %d\n#\n", cur); \
33 found[cur] = true; \
34 } \
35 if (cur == LASTKEY) { \
36 *global_null_ptr = 0; /* boom! */ \
37 } else { \
38 check##nxt(data, sz); \
39 } \
40 } \
41 }
42
43 GEN_CHECK(0, 1)
44 GEN_CHECK(1, 2)
45 GEN_CHECK(2, 3)
46 GEN_CHECK(3, 4)
47 GEN_CHECK(4, 5)
48 GEN_CHECK(5, 6)
49 GEN_CHECK(6, 0)
50
51 /* Fuzz input received from LLVM via "interrupt" */
52 extern const uint8_t *posix_fuzz_buf;
53 extern size_t posix_fuzz_sz;
54
55 K_SEM_DEFINE(fuzz_sem, 0, K_SEM_MAX_LIMIT);
56
fuzz_isr(const void * arg)57 static void fuzz_isr(const void *arg)
58 {
59 /* We could call check0() to execute the fuzz case here, but
60 * pass it through to the main thread instead to get more OS
61 * coverage.
62 */
63 k_sem_give(&fuzz_sem);
64 }
65
main(void)66 int main(void)
67 {
68 printk("Hello World! %s\n", CONFIG_BOARD);
69
70 IRQ_CONNECT(CONFIG_ARCH_POSIX_FUZZ_IRQ, 0, fuzz_isr, NULL, 0);
71 irq_enable(CONFIG_ARCH_POSIX_FUZZ_IRQ);
72
73 while (true) {
74 k_sem_take(&fuzz_sem, K_FOREVER);
75
76 /* Execute the fuzz case we got from LLVM and passed
77 * through an interrupt to this thread.
78 */
79 check0(posix_fuzz_buf, posix_fuzz_sz);
80 }
81 return 0;
82 }
83