diff options
author | Nicholas Marriott <nicholas.marriott@gmail.com> | 2020-11-09 16:41:55 +0000 |
---|---|---|
committer | Nicholas Marriott <nicholas.marriott@gmail.com> | 2020-11-09 16:44:39 +0000 |
commit | 3eb1519bd784076f63fed6678b88f918317a2124 (patch) | |
tree | b0ecce81cfe4e4612b2f8979933a7ea18a876846 | |
parent | 0dcb6e5eb4bad32ef5676c533ece81e988a1c03b (diff) | |
download | rtmux-3eb1519bd784076f63fed6678b88f918317a2124.tar.gz rtmux-3eb1519bd784076f63fed6678b88f918317a2124.tar.bz2 rtmux-3eb1519bd784076f63fed6678b88f918317a2124.zip |
Scaffold for oss-fuzz, from Sergey Nizovtsev.
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile.am | 6 | ||||
-rw-r--r-- | compat.h | 8 | ||||
-rw-r--r-- | configure.ac | 47 | ||||
-rw-r--r-- | fuzz/input-fuzzer.c | 89 | ||||
-rw-r--r-- | fuzz/input-fuzzer.dict | 8 | ||||
-rw-r--r-- | fuzz/input-fuzzer.options | 2 |
7 files changed, 159 insertions, 3 deletions
@@ -19,3 +19,5 @@ configure tmux.1.* *.dSYM cmd-parse.c +fuzz/*-fuzzer +.dirstamp diff --git a/Makefile.am b/Makefile.am index 7b84b1e9..b40e0944 100644 --- a/Makefile.am +++ b/Makefile.am @@ -202,6 +202,12 @@ if HAVE_UTF8PROC nodist_tmux_SOURCES += compat/utf8proc.c endif +if NEED_FUZZING +check_PROGRAMS = fuzz/input-fuzzer +fuzz_input_fuzzer_LDFLAGS = $(FUZZING_LIBS) +fuzz_input_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS) +endif + # Install tmux.1 in the right format. install-exec-hook: if test x@MANFORMAT@ = xmdoc; then \ @@ -52,6 +52,9 @@ #ifndef __packed #define __packed __attribute__ ((__packed__)) #endif +#ifndef __weak +#define __weak __attribute__ ((__weak__)) +#endif #ifndef ECHOPRT #define ECHOPRT 0 @@ -395,6 +398,11 @@ int utf8proc_mbtowc(wchar_t *, const char *, size_t); int utf8proc_wctomb(char *, wchar_t); #endif +#ifdef NEED_FUZZING +/* tmux.c */ +#define main __weak main +#endif + /* getopt.c */ extern int BSDopterr; extern int BSDoptind; diff --git a/configure.ac b/configure.ac index cf621835..97010df4 100644 --- a/configure.ac +++ b/configure.ac @@ -21,6 +21,26 @@ SAVED_CFLAGS="$CFLAGS" SAVED_CPPFLAGS="$CPPFLAGS" SAVED_LDFLAGS="$LDFLAGS" +# Is this oss-fuzz build? +AC_ARG_ENABLE( + fuzzing, + AC_HELP_STRING(--enable-fuzzing, build fuzzers) +) +AC_ARG_VAR( + FUZZING_LIBS, + AC_HELP_STRING(libraries to link fuzzing targets with) +) + +# Set up convenient fuzzing defaults before initializing compiler. +if test "x$enable_fuzzing" = xyes; then + AC_DEFINE(NEED_FUZZING) + test "x$CC" == x && CC=clang + test "x$FUZZING_LIBS" == x && \ + FUZZING_LIBS="-fsanitize=fuzzer" + test "x$SAVED_CFLAGS" == x && \ + AM_CFLAGS="-g -fsanitize=fuzzer-no-link,address" +fi + # Set up the compiler in two different ways and say yes we may want to install. AC_PROG_CC AM_PROG_CC_C_O @@ -54,8 +74,11 @@ if test "x$enable_static" = xyes; then LDFLAGS="$AM_LDFLAGS $SAVED_LDFLAGS" fi +# Do we need fuzzers? +AM_CONDITIONAL(NEED_FUZZING, test "x$enable_fuzzing" = xyes) + # Is this gcc? -AM_CONDITIONAL(IS_GCC, test "x$GCC" = xyes) +AM_CONDITIONAL(IS_GCC, test "x$GCC" = xyes -a "x$enable_fuzzing" != xyes) # Is this Sun CC? AC_EGREP_CPP( @@ -117,8 +140,6 @@ AC_REPLACE_FUNCS([ \ getline \ getprogname \ memmem \ - recallocarray \ - reallocarray \ setenv \ setproctitle \ strcasestr \ @@ -130,6 +151,26 @@ AC_REPLACE_FUNCS([ \ ]) AC_FUNC_STRNLEN +# Clang sanitizers wrap reallocarray even if it isn't available on the target +# system. When compiled it always returns NULL and crashes the program. To +# detect this we need a more complicated test. +AC_MSG_CHECKING([for working reallocarray]) +AC_RUN_IFELSE([AC_LANG_PROGRAM( + [#include <stdlib.h>], + [return (reallocarray(NULL, 1, 1) == NULL);] + )], + AC_MSG_RESULT(yes), + [AC_LIBOBJ(reallocarray) AC_MSG_RESULT([no])] +) +AC_MSG_CHECKING([for working recallocarray]) +AC_RUN_IFELSE([AC_LANG_PROGRAM( + [#include <stdlib.h>], + [return (recallocarray(NULL, 1, 1, 1) == NULL);] + )], + AC_MSG_RESULT(yes), + [AC_LIBOBJ(recallocarray) AC_MSG_RESULT([no])] +) + # Look for clock_gettime. Must come before event_init. AC_SEARCH_LIBS(clock_gettime, rt) diff --git a/fuzz/input-fuzzer.c b/fuzz/input-fuzzer.c new file mode 100644 index 00000000..27f2be3d --- /dev/null +++ b/fuzz/input-fuzzer.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2020 Sergey Nizovtsev <snizovtsev@gmail.com> + * + * 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 MIND, 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. + */ + +#include <stddef.h> +#include <assert.h> + +#include "tmux.h" + +#define FUZZER_MAXLEN 512 +#define PANE_WIDTH 80 +#define PANE_HEIGHT 25 + +struct event_base *libevent; + +int +LLVMFuzzerTestOneInput(const unsigned char *data, size_t size) +{ + struct bufferevent *vpty[2]; + struct window *w; + struct window_pane *wp; + int error; + + /* + * Since AFL doesn't support -max_len paramenter we have to + * discard long inputs manually. + */ + if (size > FUZZER_MAXLEN) + return 0; + + w = window_create(PANE_WIDTH, PANE_HEIGHT, 0, 0); + wp = window_add_pane(w, NULL, 0, 0); + bufferevent_pair_new(libevent, BEV_OPT_CLOSE_ON_FREE, vpty); + wp->ictx = input_init(wp, vpty[0]); + window_add_ref(w, __func__); + + input_parse_buffer(wp, (u_char*) data, size); + while (cmdq_next(NULL) != 0) + ; + error = event_base_loop(libevent, EVLOOP_NONBLOCK); + if (error == -1) + errx(1, "event_base_loop failed"); + + assert(w->references == 1); + window_remove_ref(w, __func__); + + bufferevent_free(vpty[0]); + bufferevent_free(vpty[1]); + + return 0; +} + +int +LLVMFuzzerInitialize(__unused int *argc, __unused char ***argv) +{ + const struct options_table_entry *oe; + + global_environ = environ_create(); + global_options = options_create(NULL); + global_s_options = options_create(NULL); + global_w_options = options_create(NULL); + for (oe = options_table; oe->name != NULL; oe++) { + if (oe->scope & OPTIONS_TABLE_SERVER) + options_default(global_options, oe); + if (oe->scope & OPTIONS_TABLE_SESSION) + options_default(global_s_options, oe); + if (oe->scope & OPTIONS_TABLE_WINDOW) + options_default(global_w_options, oe); + } + libevent = osdep_event_init(); + + options_set_number(global_w_options, "monitor-bell", 0); + options_set_number(global_w_options, "allow-rename", 1); + options_set_number(global_options, "set-clipboard", 2); + + return 0; +} diff --git a/fuzz/input-fuzzer.dict b/fuzz/input-fuzzer.dict new file mode 100644 index 00000000..2091b970 --- /dev/null +++ b/fuzz/input-fuzzer.dict @@ -0,0 +1,8 @@ +"\x1b[" +"1000" +"2004" +"1049" +"38;2" +"100;" +"tmux;" +"rgb:00/00/00" diff --git a/fuzz/input-fuzzer.options b/fuzz/input-fuzzer.options new file mode 100644 index 00000000..5d468bc6 --- /dev/null +++ b/fuzz/input-fuzzer.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 512 |