etc~ scripts and random things |
| git clone https://github.com/djnnvx/etc.git |
| log | files | refs | archive |
mock_syscalls.c (2817B)
1 /* 2 * mock_syscalls.c — recv/send overrides via --wrap linker flags. 3 * 4 * afl-clang-fast links this with -Wl,--wrap=recv -Wl,--wrap=send so that 5 * all recv() calls inside the compiled usbip objects read from g_fuzz_buf 6 * instead of a real socket. send() is a no-op (output discarded). 7 * 8 * The fuzz buffer is populated by each harness's main() / LLVMFuzzerTestOneInput 9 * via fuzz_reset() from usbip_fuzz.h. 10 */ 11 12 #include <stddef.h> 13 #include <stdint.h> 14 #include <string.h> 15 #include <sys/types.h> 16 #include <sys/socket.h> 17 18 #define FUZZ_BUF_MAX (1 << 16) 19 20 uint8_t g_fuzz_buf[FUZZ_BUF_MAX]; 21 size_t g_fuzz_len; 22 size_t g_fuzz_offset; 23 24 /* usbip_debug_flag referenced by logging macros; keep at 0 */ 25 unsigned long usbip_debug_flag = 0; 26 27 /* 28 * udev_context — global udev handle owned by usbip_host_common.c which we 29 * don't compile for the fuzz build. Provide a NULL stub; the network 30 * parsing paths we target never call udev_device_new_from_subsystem_sysname. 31 */ 32 struct udev; 33 struct udev *udev_context = NULL; 34 35 /* 36 * __wrap_recv — intercepts every recv() call from the usbip objects. 37 * Serves data from g_fuzz_buf in order; returns 0 (EOF) when exhausted. 38 * 39 * Partial reads are intentionally allowed so usbip_net_xmit's retry loop 40 * sees realistic short-read behaviour and AFL++ can explore both the 41 * "got full header" and "short read" code paths. 42 */ 43 ssize_t __wrap_recv(int fd, void *buf, size_t len, int flags) 44 { 45 (void)fd; 46 (void)flags; 47 48 if (g_fuzz_offset >= g_fuzz_len) 49 return 0; /* EOF — caller sees empty read and returns error */ 50 51 size_t avail = g_fuzz_len - g_fuzz_offset; 52 size_t n = len < avail ? len : avail; 53 memcpy(buf, g_fuzz_buf + g_fuzz_offset, n); 54 g_fuzz_offset += n; 55 return (ssize_t)n; 56 } 57 58 /* 59 * __wrap_send — silently discards all outgoing data. 60 * Pretends to have sent everything so callers don't error out. 61 */ 62 ssize_t __wrap_send(int fd, const void *buf, size_t len, int flags) 63 { 64 (void)fd; 65 (void)buf; 66 (void)flags; 67 return (ssize_t)len; 68 } 69 70 /* Some usbip code paths use write() for logging; silence those too */ 71 ssize_t __wrap_write(int fd, const void *buf, size_t len) 72 { 73 extern ssize_t __real_write(int, const void *, size_t); 74 /* 75 * Pass through: 76 * fd 2 — stderr (ASAN/abort messages need to reach the terminal) 77 * fd 198 — AFL++ forkserver control pipe (FORKSRV_FD) 78 * fd 199 — AFL++ forkserver status pipe (FORKSRV_FD+1) 79 * 80 * AFL++ runtime calls write(199, hello, 4) to hand-shake with afl-fuzz. 81 * Without this pass-through the hello is silently discarded and AFL++ 82 * deadlocks waiting for the forkserver to become ready. 83 */ 84 if (fd == 2 || fd == 198 || fd == 199) 85 return __real_write(fd, buf, len); 86 (void)buf; 87 return (ssize_t)len; 88 }