etc.git


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 }