summaryrefslogtreecommitdiffstats
path: root/lib/fuzzstub/fuzzstub.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/fuzzstub/fuzzstub.c')
-rw-r--r--lib/fuzzstub/fuzzstub.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/lib/fuzzstub/fuzzstub.c b/lib/fuzzstub/fuzzstub.c
new file mode 100644
index 0000000..bc28cad
--- /dev/null
+++ b/lib/fuzzstub/fuzzstub.c
@@ -0,0 +1,133 @@
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2021 Todd C. Miller <Todd.Miller@sudo.ws>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This is an open source non-commercial project. Dear PVS-Studio, please check it.
+ * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+ */
+
+#include <config.h>
+
+#include <sys/stat.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#if defined(HAVE_STDINT_H)
+# include <stdint.h>
+#elif defined(HAVE_INTTYPES_H)
+# include <inttypes.h>
+#endif
+
+#include "sudo_compat.h"
+#include "sudo_util.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+sudo_dso_public int main(int argc, char *argv[]);
+
+/*
+ * Simple driver for fuzzers built for LLVM libfuzzer.
+ * This stub library allows fuzz targets to be built and run without
+ * libfuzzer. No actual fuzzing will occur but the provided inputs
+ * will be tested.
+ */
+int
+main(int argc, char *argv[])
+{
+ struct timespec start_time, stop_time;
+ size_t filesize, bufsize = 0;
+ ssize_t nread;
+ struct stat sb;
+ uint8_t *buf = NULL;
+ int fd, i, errors = 0;
+ int verbose = 0;
+ long ms;
+
+ /* Test provided input files. */
+ for (i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+ if (*arg == '-') {
+ if (strncmp(arg, "-verbosity=", sizeof("-verbosity=") - 1) == 0) {
+ verbose = atoi(arg + sizeof("-verbosity=") - 1);
+ }
+ continue;
+ }
+ fd = open(arg, O_RDONLY);
+ if (fd == -1 || fstat(fd, &sb) != 0) {
+ fprintf(stderr, "open %s: %s\n", arg, strerror(errno));
+ if (fd != -1)
+ close(fd);
+ errors++;
+ continue;
+ }
+#ifndef __LP64__
+ if (sizeof(sb.st_size) > sizeof(size_t) && sb.st_size > SSIZE_MAX) {
+ errno = E2BIG;
+ fprintf(stderr, "%s: %s\n", arg, strerror(errno));
+ close(fd);
+ errors++;
+ continue;
+ }
+#endif
+ filesize = sb.st_size;
+ if (bufsize < filesize) {
+ void *tmp = realloc(buf, filesize);
+ if (tmp == NULL) {
+ fprintf(stderr, "realloc: %s\n", strerror(errno));
+ close(fd);
+ errors++;
+ continue;
+ }
+ buf = tmp;
+ bufsize = filesize;
+ }
+ nread = read(fd, buf, filesize);
+ if ((size_t)nread != filesize) {
+ if (nread == -1)
+ fprintf(stderr, "read %s: %s\n", arg, strerror(errno));
+ else
+ fprintf(stderr, "read %s: short read\n", arg);
+ close(fd);
+ errors++;
+ continue;
+ }
+ close(fd);
+
+ /* NOTE: doesn't support LLVMFuzzerInitialize() (but we don't use it) */
+ if (verbose > 0) {
+ fprintf(stderr, "Running: %s\n", arg);
+ sudo_gettime_mono(&start_time);
+ }
+ LLVMFuzzerTestOneInput(buf, nread);
+ if (verbose > 0) {
+ sudo_gettime_mono(&stop_time);
+ sudo_timespecsub(&stop_time, &start_time, &stop_time);
+ ms = (stop_time.tv_sec * 1000) + (stop_time.tv_nsec / 1000000);
+ fprintf(stderr, "Executed %s in %ld ms\n", arg, ms);
+ }
+ }
+ free(buf);
+
+ return errors;
+}