1*35c0a8c4SKyle Evans /*- 2*35c0a8c4SKyle Evans * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org> 3*35c0a8c4SKyle Evans * 4*35c0a8c4SKyle Evans * SPDX-License-Identifier: BSD-2-Clause 5*35c0a8c4SKyle Evans */ 6*35c0a8c4SKyle Evans 7*35c0a8c4SKyle Evans #include <sys/param.h> 8*35c0a8c4SKyle Evans #include <sys/socket.h> 9*35c0a8c4SKyle Evans 10*35c0a8c4SKyle Evans #include <assert.h> 11*35c0a8c4SKyle Evans #include <pthread.h> 12*35c0a8c4SKyle Evans #include <signal.h> 13*35c0a8c4SKyle Evans #include <stdbool.h> 14*35c0a8c4SKyle Evans #include <stdio.h> 15*35c0a8c4SKyle Evans #include <unistd.h> 16*35c0a8c4SKyle Evans 17*35c0a8c4SKyle Evans #include <libder.h> 18*35c0a8c4SKyle Evans 19*35c0a8c4SKyle Evans #include "fuzzers.h" 20*35c0a8c4SKyle Evans 21*35c0a8c4SKyle Evans struct supply_data { 22*35c0a8c4SKyle Evans const uint8_t *data; 23*35c0a8c4SKyle Evans volatile size_t datasz; 24*35c0a8c4SKyle Evans int socket; 25*35c0a8c4SKyle Evans }; 26*35c0a8c4SKyle Evans 27*35c0a8c4SKyle Evans static void * 28*35c0a8c4SKyle Evans supply_thread(void *data) 29*35c0a8c4SKyle Evans { 30*35c0a8c4SKyle Evans struct supply_data *sdata = data; 31*35c0a8c4SKyle Evans size_t sz = sdata->datasz; 32*35c0a8c4SKyle Evans ssize_t writesz; 33*35c0a8c4SKyle Evans 34*35c0a8c4SKyle Evans do { 35*35c0a8c4SKyle Evans writesz = write(sdata->socket, sdata->data, sz); 36*35c0a8c4SKyle Evans 37*35c0a8c4SKyle Evans data += writesz; 38*35c0a8c4SKyle Evans sz -= writesz; 39*35c0a8c4SKyle Evans } while (sz != 0 && writesz > 0); 40*35c0a8c4SKyle Evans 41*35c0a8c4SKyle Evans sdata->datasz = sz; 42*35c0a8c4SKyle Evans shutdown(sdata->socket, SHUT_RDWR); 43*35c0a8c4SKyle Evans close(sdata->socket); 44*35c0a8c4SKyle Evans 45*35c0a8c4SKyle Evans return (NULL); 46*35c0a8c4SKyle Evans } 47*35c0a8c4SKyle Evans 48*35c0a8c4SKyle Evans static int 49*35c0a8c4SKyle Evans fuzz_fd(const struct fuzz_params *fparams, const uint8_t *data, size_t sz) 50*35c0a8c4SKyle Evans { 51*35c0a8c4SKyle Evans struct supply_data sdata; 52*35c0a8c4SKyle Evans struct libder_ctx *ctx; 53*35c0a8c4SKyle Evans struct libder_object *obj; 54*35c0a8c4SKyle Evans size_t totalsz; 55*35c0a8c4SKyle Evans int sockets[2]; 56*35c0a8c4SKyle Evans pid_t pid; 57*35c0a8c4SKyle Evans int ret; 58*35c0a8c4SKyle Evans 59*35c0a8c4SKyle Evans ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, 60*35c0a8c4SKyle Evans &sockets[0]); 61*35c0a8c4SKyle Evans if (ret == -1) 62*35c0a8c4SKyle Evans return (-1); 63*35c0a8c4SKyle Evans 64*35c0a8c4SKyle Evans sdata.data = data; 65*35c0a8c4SKyle Evans sdata.datasz = sz; 66*35c0a8c4SKyle Evans sdata.socket = sockets[1]; 67*35c0a8c4SKyle Evans signal(SIGCHLD, SIG_IGN); 68*35c0a8c4SKyle Evans pid = fork(); 69*35c0a8c4SKyle Evans if (pid == -1) { 70*35c0a8c4SKyle Evans close(sockets[0]); 71*35c0a8c4SKyle Evans close(sockets[1]); 72*35c0a8c4SKyle Evans return (-1); 73*35c0a8c4SKyle Evans } 74*35c0a8c4SKyle Evans 75*35c0a8c4SKyle Evans if (pid == 0) { 76*35c0a8c4SKyle Evans close(sockets[0]); 77*35c0a8c4SKyle Evans supply_thread(&sdata); 78*35c0a8c4SKyle Evans _exit(0); 79*35c0a8c4SKyle Evans } else { 80*35c0a8c4SKyle Evans close(sockets[1]); 81*35c0a8c4SKyle Evans } 82*35c0a8c4SKyle Evans 83*35c0a8c4SKyle Evans totalsz = 0; 84*35c0a8c4SKyle Evans ret = 0; 85*35c0a8c4SKyle Evans ctx = libder_open(); 86*35c0a8c4SKyle Evans libder_set_strict(ctx, !!fparams->strict); 87*35c0a8c4SKyle Evans while (totalsz < sz) { 88*35c0a8c4SKyle Evans size_t readsz = 0; 89*35c0a8c4SKyle Evans 90*35c0a8c4SKyle Evans obj = libder_read_fd(ctx, sockets[0], &readsz); 91*35c0a8c4SKyle Evans libder_obj_free(obj); 92*35c0a8c4SKyle Evans 93*35c0a8c4SKyle Evans /* 94*35c0a8c4SKyle Evans * Even invalid reads should consume at least one byte. 95*35c0a8c4SKyle Evans */ 96*35c0a8c4SKyle Evans assert(readsz != 0); 97*35c0a8c4SKyle Evans 98*35c0a8c4SKyle Evans totalsz += readsz; 99*35c0a8c4SKyle Evans if (readsz == 0) 100*35c0a8c4SKyle Evans break; 101*35c0a8c4SKyle Evans } 102*35c0a8c4SKyle Evans 103*35c0a8c4SKyle Evans assert(totalsz == sz); 104*35c0a8c4SKyle Evans libder_close(ctx); 105*35c0a8c4SKyle Evans close(sockets[0]); 106*35c0a8c4SKyle Evans 107*35c0a8c4SKyle Evans return (ret); 108*35c0a8c4SKyle Evans } 109*35c0a8c4SKyle Evans 110*35c0a8c4SKyle Evans static int 111*35c0a8c4SKyle Evans fuzz_file(const struct fuzz_params *fparams, const uint8_t *data, size_t sz) 112*35c0a8c4SKyle Evans { 113*35c0a8c4SKyle Evans FILE *fp; 114*35c0a8c4SKyle Evans struct libder_ctx *ctx; 115*35c0a8c4SKyle Evans struct libder_object *obj; 116*35c0a8c4SKyle Evans size_t totalsz; 117*35c0a8c4SKyle Evans int ret; 118*35c0a8c4SKyle Evans 119*35c0a8c4SKyle Evans if (fparams->buftype >= BUFFER_END) 120*35c0a8c4SKyle Evans return (-1); 121*35c0a8c4SKyle Evans 122*35c0a8c4SKyle Evans fp = fmemopen(__DECONST(void *, data), sz, "rb"); 123*35c0a8c4SKyle Evans assert(fp != NULL); 124*35c0a8c4SKyle Evans 125*35c0a8c4SKyle Evans switch (fparams->buftype) { 126*35c0a8c4SKyle Evans case BUFFER_NONE: 127*35c0a8c4SKyle Evans setvbuf(fp, NULL, 0, _IONBF); 128*35c0a8c4SKyle Evans break; 129*35c0a8c4SKyle Evans case BUFFER_FULL: 130*35c0a8c4SKyle Evans setvbuf(fp, NULL, 0, _IOFBF); 131*35c0a8c4SKyle Evans break; 132*35c0a8c4SKyle Evans case BUFFER_END: 133*35c0a8c4SKyle Evans assert(0); 134*35c0a8c4SKyle Evans } 135*35c0a8c4SKyle Evans 136*35c0a8c4SKyle Evans totalsz = 0; 137*35c0a8c4SKyle Evans ret = 0; 138*35c0a8c4SKyle Evans ctx = libder_open(); 139*35c0a8c4SKyle Evans libder_set_strict(ctx, !!fparams->strict); 140*35c0a8c4SKyle Evans while (!feof(fp)) { 141*35c0a8c4SKyle Evans size_t readsz = 0; 142*35c0a8c4SKyle Evans 143*35c0a8c4SKyle Evans obj = libder_read_file(ctx, fp, &readsz); 144*35c0a8c4SKyle Evans libder_obj_free(obj); 145*35c0a8c4SKyle Evans 146*35c0a8c4SKyle Evans if (obj == NULL) 147*35c0a8c4SKyle Evans assert(readsz != 0 || feof(fp)); 148*35c0a8c4SKyle Evans else 149*35c0a8c4SKyle Evans assert(readsz != 0); 150*35c0a8c4SKyle Evans 151*35c0a8c4SKyle Evans totalsz += readsz; 152*35c0a8c4SKyle Evans } 153*35c0a8c4SKyle Evans 154*35c0a8c4SKyle Evans assert(totalsz == sz); 155*35c0a8c4SKyle Evans libder_close(ctx); 156*35c0a8c4SKyle Evans fclose(fp); 157*35c0a8c4SKyle Evans 158*35c0a8c4SKyle Evans return (ret); 159*35c0a8c4SKyle Evans } 160*35c0a8c4SKyle Evans 161*35c0a8c4SKyle Evans static int 162*35c0a8c4SKyle Evans fuzz_plain(const struct fuzz_params *fparams, const uint8_t *data, size_t sz) 163*35c0a8c4SKyle Evans { 164*35c0a8c4SKyle Evans struct libder_ctx *ctx; 165*35c0a8c4SKyle Evans struct libder_object *obj; 166*35c0a8c4SKyle Evans int ret; 167*35c0a8c4SKyle Evans 168*35c0a8c4SKyle Evans if (sz == 0) 169*35c0a8c4SKyle Evans return (-1); 170*35c0a8c4SKyle Evans 171*35c0a8c4SKyle Evans ret = 0; 172*35c0a8c4SKyle Evans ctx = libder_open(); 173*35c0a8c4SKyle Evans libder_set_strict(ctx, !!fparams->strict); 174*35c0a8c4SKyle Evans do { 175*35c0a8c4SKyle Evans size_t readsz; 176*35c0a8c4SKyle Evans 177*35c0a8c4SKyle Evans readsz = sz; 178*35c0a8c4SKyle Evans obj = libder_read(ctx, data, &readsz); 179*35c0a8c4SKyle Evans libder_obj_free(obj); 180*35c0a8c4SKyle Evans 181*35c0a8c4SKyle Evans if (obj == NULL) 182*35c0a8c4SKyle Evans assert(readsz != 0 || readsz == sz); 183*35c0a8c4SKyle Evans else 184*35c0a8c4SKyle Evans assert(readsz != 0); 185*35c0a8c4SKyle Evans 186*35c0a8c4SKyle Evans /* 187*35c0a8c4SKyle Evans * If we hit an entirely invalid segment of the buffer, we'll 188*35c0a8c4SKyle Evans * just skip a byte and try again. 189*35c0a8c4SKyle Evans */ 190*35c0a8c4SKyle Evans data += MAX(1, readsz); 191*35c0a8c4SKyle Evans sz -= MAX(1, readsz); 192*35c0a8c4SKyle Evans } while (sz != 0); 193*35c0a8c4SKyle Evans 194*35c0a8c4SKyle Evans libder_close(ctx); 195*35c0a8c4SKyle Evans 196*35c0a8c4SKyle Evans return (ret); 197*35c0a8c4SKyle Evans }; 198*35c0a8c4SKyle Evans 199*35c0a8c4SKyle Evans static bool 200*35c0a8c4SKyle Evans validate_padding(const struct fuzz_params *fparams) 201*35c0a8c4SKyle Evans { 202*35c0a8c4SKyle Evans const uint8_t *end = (const void *)(fparams + 1); 203*35c0a8c4SKyle Evans const uint8_t *pad = (const uint8_t *)&fparams->PARAM_PAD_START; 204*35c0a8c4SKyle Evans 205*35c0a8c4SKyle Evans while (pad < end) { 206*35c0a8c4SKyle Evans if (*pad++ != 0) 207*35c0a8c4SKyle Evans return (false); 208*35c0a8c4SKyle Evans } 209*35c0a8c4SKyle Evans 210*35c0a8c4SKyle Evans return (true); 211*35c0a8c4SKyle Evans } 212*35c0a8c4SKyle Evans 213*35c0a8c4SKyle Evans int 214*35c0a8c4SKyle Evans LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) 215*35c0a8c4SKyle Evans { 216*35c0a8c4SKyle Evans const struct fuzz_params *fparams; 217*35c0a8c4SKyle Evans 218*35c0a8c4SKyle Evans if (sz <= sizeof(*fparams)) 219*35c0a8c4SKyle Evans return (-1); 220*35c0a8c4SKyle Evans 221*35c0a8c4SKyle Evans fparams = (const void *)data; 222*35c0a8c4SKyle Evans if (fparams->type >= STREAM_END) 223*35c0a8c4SKyle Evans return (-1); 224*35c0a8c4SKyle Evans 225*35c0a8c4SKyle Evans if (!validate_padding(fparams)) 226*35c0a8c4SKyle Evans return (-1); 227*35c0a8c4SKyle Evans 228*35c0a8c4SKyle Evans data += sizeof(*fparams); 229*35c0a8c4SKyle Evans sz -= sizeof(*fparams); 230*35c0a8c4SKyle Evans 231*35c0a8c4SKyle Evans if (fparams->type != STREAM_FILE && fparams->buftype != BUFFER_NONE) 232*35c0a8c4SKyle Evans return (-1); 233*35c0a8c4SKyle Evans 234*35c0a8c4SKyle Evans switch (fparams->type) { 235*35c0a8c4SKyle Evans case STREAM_FD: 236*35c0a8c4SKyle Evans return (fuzz_fd(fparams, data, sz)); 237*35c0a8c4SKyle Evans case STREAM_FILE: 238*35c0a8c4SKyle Evans return (fuzz_file(fparams, data, sz)); 239*35c0a8c4SKyle Evans case STREAM_PLAIN: 240*35c0a8c4SKyle Evans return (fuzz_plain(fparams, data, sz)); 241*35c0a8c4SKyle Evans case STREAM_END: 242*35c0a8c4SKyle Evans assert(0); 243*35c0a8c4SKyle Evans } 244*35c0a8c4SKyle Evans 245*35c0a8c4SKyle Evans __builtin_trap(); 246*35c0a8c4SKyle Evans } 247