Path: blob/main/contrib/libder/tests/fuzz_stream.c
39564 views
/*-1* Copyright (c) 2024 Kyle Evans <[email protected]>2*3* SPDX-License-Identifier: BSD-2-Clause4*/56#include <sys/param.h>7#include <sys/socket.h>89#include <assert.h>10#include <pthread.h>11#include <signal.h>12#include <stdbool.h>13#include <stdio.h>14#include <unistd.h>1516#include <libder.h>1718#include "fuzzers.h"1920struct supply_data {21const uint8_t *data;22volatile size_t datasz;23int socket;24};2526static void *27supply_thread(void *data)28{29struct supply_data *sdata = data;30size_t sz = sdata->datasz;31ssize_t writesz;3233do {34writesz = write(sdata->socket, sdata->data, sz);3536data += writesz;37sz -= writesz;38} while (sz != 0 && writesz > 0);3940sdata->datasz = sz;41shutdown(sdata->socket, SHUT_RDWR);42close(sdata->socket);4344return (NULL);45}4647static int48fuzz_fd(const struct fuzz_params *fparams, const uint8_t *data, size_t sz)49{50struct supply_data sdata;51struct libder_ctx *ctx;52struct libder_object *obj;53size_t totalsz;54int sockets[2];55pid_t pid;56int ret;5758ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0,59&sockets[0]);60if (ret == -1)61return (-1);6263sdata.data = data;64sdata.datasz = sz;65sdata.socket = sockets[1];66signal(SIGCHLD, SIG_IGN);67pid = fork();68if (pid == -1) {69close(sockets[0]);70close(sockets[1]);71return (-1);72}7374if (pid == 0) {75close(sockets[0]);76supply_thread(&sdata);77_exit(0);78} else {79close(sockets[1]);80}8182totalsz = 0;83ret = 0;84ctx = libder_open();85libder_set_strict(ctx, !!fparams->strict);86while (totalsz < sz) {87size_t readsz = 0;8889obj = libder_read_fd(ctx, sockets[0], &readsz);90libder_obj_free(obj);9192/*93* Even invalid reads should consume at least one byte.94*/95assert(readsz != 0);9697totalsz += readsz;98if (readsz == 0)99break;100}101102assert(totalsz == sz);103libder_close(ctx);104close(sockets[0]);105106return (ret);107}108109static int110fuzz_file(const struct fuzz_params *fparams, const uint8_t *data, size_t sz)111{112FILE *fp;113struct libder_ctx *ctx;114struct libder_object *obj;115size_t totalsz;116int ret;117118if (fparams->buftype >= BUFFER_END)119return (-1);120121fp = fmemopen(__DECONST(void *, data), sz, "rb");122assert(fp != NULL);123124switch (fparams->buftype) {125case BUFFER_NONE:126setvbuf(fp, NULL, 0, _IONBF);127break;128case BUFFER_FULL:129setvbuf(fp, NULL, 0, _IOFBF);130break;131case BUFFER_END:132assert(0);133}134135totalsz = 0;136ret = 0;137ctx = libder_open();138libder_set_strict(ctx, !!fparams->strict);139while (!feof(fp)) {140size_t readsz = 0;141142obj = libder_read_file(ctx, fp, &readsz);143libder_obj_free(obj);144145if (obj == NULL)146assert(readsz != 0 || feof(fp));147else148assert(readsz != 0);149150totalsz += readsz;151}152153assert(totalsz == sz);154libder_close(ctx);155fclose(fp);156157return (ret);158}159160static int161fuzz_plain(const struct fuzz_params *fparams, const uint8_t *data, size_t sz)162{163struct libder_ctx *ctx;164struct libder_object *obj;165int ret;166167if (sz == 0)168return (-1);169170ret = 0;171ctx = libder_open();172libder_set_strict(ctx, !!fparams->strict);173do {174size_t readsz;175176readsz = sz;177obj = libder_read(ctx, data, &readsz);178libder_obj_free(obj);179180if (obj == NULL)181assert(readsz != 0 || readsz == sz);182else183assert(readsz != 0);184185/*186* If we hit an entirely invalid segment of the buffer, we'll187* just skip a byte and try again.188*/189data += MAX(1, readsz);190sz -= MAX(1, readsz);191} while (sz != 0);192193libder_close(ctx);194195return (ret);196};197198static bool199validate_padding(const struct fuzz_params *fparams)200{201const uint8_t *end = (const void *)(fparams + 1);202const uint8_t *pad = (const uint8_t *)&fparams->PARAM_PAD_START;203204while (pad < end) {205if (*pad++ != 0)206return (false);207}208209return (true);210}211212int213LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz)214{215const struct fuzz_params *fparams;216217if (sz <= sizeof(*fparams))218return (-1);219220fparams = (const void *)data;221if (fparams->type >= STREAM_END)222return (-1);223224if (!validate_padding(fparams))225return (-1);226227data += sizeof(*fparams);228sz -= sizeof(*fparams);229230if (fparams->type != STREAM_FILE && fparams->buftype != BUFFER_NONE)231return (-1);232233switch (fparams->type) {234case STREAM_FD:235return (fuzz_fd(fparams, data, sz));236case STREAM_FILE:237return (fuzz_file(fparams, data, sz));238case STREAM_PLAIN:239return (fuzz_plain(fparams, data, sz));240case STREAM_END:241assert(0);242}243244__builtin_trap();245}246247248