From c8df6d0f5bb7d251a2f7e23c3c3efd179b0f2779 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Mon, 1 Jan 2007 21:35:54 +0000 Subject: [PATCH] * Implemented signal handling. * Updated documentation accordingly and improved a few parts. --- doc/zzuf.1 | 70 ++++++++++++++++++++++---- src/Makefile.am | 3 +- src/libzzuf.c | 10 +++- src/libzzuf.h | 3 +- src/load-signal.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++ src/load.h | 1 + src/zzuf.c | 28 +++++++---- 7 files changed, 214 insertions(+), 26 deletions(-) create mode 100644 src/load-signal.c diff --git a/doc/zzuf.1 b/doc/zzuf.1 index cc5e573..0947e40 100644 --- a/doc/zzuf.1 +++ b/doc/zzuf.1 @@ -4,7 +4,7 @@ zzuf \- multiple purpose fuzzer .SH SYNOPSIS .B zzuf [ -.B \-vqdhic +.B \-cdhiqSv ] [ .B \-r .I ratio @@ -86,8 +86,8 @@ Do not fuzz files whose name matches the .B regular expression. This option supersedes anything that is specified by the .B \-\-exclude -flag. Use this for instance if you do not know for sure what files your -application is going to read, but do not want it to fuzz files in the +flag. Use this for instance if you are unsure of what files your +application is going to read and do not want it to fuzz files in the .B /etc directory. @@ -119,11 +119,14 @@ configuration files at startup and you only want specific files to be fuzzed. Multiple .B \-I flags can be specified, in which case files matching any one of the regular -expressions will be fuzzed. +expressions will be fuzzed. See also the +.B \-c +flag. .TP .B \-q, \-\-quiet Hide the output of the fuzzed application. This is useful if the application -is very verbose but only its exit code is really useful to you. +is very verbose but only its exit code or signaled status is really useful to +you. .TP .B \-r, \-\-ratio Specify the amount of bits that will be randomly fuzzed. A value of 0 @@ -153,6 +156,27 @@ If an interval is specified, will run the application several times, each time with a different seed, and report the behaviour of each run. .TP +.B \-S, \-\-signal +Prevent children from installing signal handlers for signals that usually +cause coredumps. These signals are +.BR SIGABRT , +.BR SIGFPE , +.BR SIGILL , +.BR SIGQUIT , +.BR SIGSEGV , +.B SIGTRAP +and, if available on the running platform, +.BR SIGSYS , +.BR SIGEMT , +.BR SIGBUS , +.B SIGXCPU +and +.BR SIGXFSZ . +Instead of calling the signal handler, the application will simply crash. If +you do not want core dumps, you should set appropriate limits with the +.B limit coredumpsize +command. See your shell's documentation on how to set such limits. +.TP .B \-T, \-\-max\-time Automatically terminate child processes that run for more than .B @@ -187,7 +211,7 @@ as the original input and excluding .B .xml files from fuzzing (because .B convert -will also open its own configuration files and we do not want +will also open its own XML configuration files and we do not want .B zzuf to fuzz them): .nf @@ -215,12 +239,28 @@ to reproduce the same behaviour without using .B % vlc fuzzy-movie.avi .fi -Fuzz +Fuzz 2% of .BR mplayer 's -input with seeds 0 to 9999, launching up to 3 simultaneous child processes -and killing -.BR mplayer -if it takes more than one minute to read the file: +input bits +.RB ( \-r +.BR 0.02 ) +with seeds 0 to 9999 +.RB ( \-s +.BR 0:10000 ), +disabling its standard output messages +.RB ( \-q ), +launching up to three simultaneous child processes +.RB ( \-F +.BR 3 ), +killing +.B mplayer +if it takes more than one minute to read the file +.RB ( \-T +.BR 60 ) +and disabling its +.B SIGSEGV +signal handler +.RB ( \-S ): .fn .B % zzuf -c -q -s 0:10000 -F 3 -T 60 -r 0.02 mplayer movie.avi -- -benchmark -vo null -fps 1000 @@ -239,6 +279,14 @@ etc. One important unimplemented function is Network fuzzing is not implemented. It is not yet possible to insert or drop bytes from the input, to fuzz according to the file format, or to do all these complicated operations. They are planned, though. + +Due to +.B zzuf +using +.B LD_PRELOAD +to run its child processes, it will fail in the presence of any mechanism +that disables preloading. For instance setuid root binaries will not be +fuzzed. .RI .SH AUTHOR .B Zzuf diff --git a/src/Makefile.am b/src/Makefile.am index 88f3675..2d2ae07 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,7 +5,8 @@ zzuf_CPPFLAGS = -DLIBDIR=\"$(libdir)/zzuf\" pkglib_LTLIBRARIES = libzzuf.la libzzuf_la_SOURCES = libzzuf.c libzzuf.h fuzz.c fuzz.h debug.c debug.h \ - load-fd.c load-stream.c load.h random.c random.h + load-fd.c load-signal.c load-stream.c load.h \ + random.c random.h libzzuf_la_LDFLAGS = -module -avoid-version -no-undefined libzzuf_la_LIBADD = -ldl diff --git a/src/libzzuf.c b/src/libzzuf.c index 5ae03ca..ad837ec 100644 --- a/src/libzzuf.c +++ b/src/libzzuf.c @@ -40,8 +40,9 @@ /* Global variables */ int _zz_ready = 0; int _zz_hasdebug = 0; -int _zz_seed = 0; float _zz_ratio = 0.004f; +int _zz_seed = 0; +int _zz_signal = 0; /* Local variables */ static regex_t * re_include = NULL; @@ -57,7 +58,7 @@ void _zz_init(void) char *tmp; tmp = getenv("ZZUF_DEBUG"); - if(tmp && *tmp) + if(tmp && *tmp == '1') _zz_hasdebug = 1; tmp = getenv("ZZUF_SEED"); @@ -86,6 +87,10 @@ void _zz_init(void) regcomp(re_exclude, tmp, REG_EXTENDED); } + tmp = getenv("ZZUF_SIGNAL"); + if(tmp && *tmp == '1') + _zz_signal = 1; + _zz_fd_init(); tmp = getenv("ZZUF_STDIN"); @@ -93,6 +98,7 @@ void _zz_init(void) _zz_register(0); _zz_load_fd(); + _zz_load_signal(); _zz_load_stream(); _zz_ready = 1; diff --git a/src/libzzuf.h b/src/libzzuf.h index f4346e9..6a23334 100644 --- a/src/libzzuf.h +++ b/src/libzzuf.h @@ -31,8 +31,9 @@ struct fuzz /* Internal variables */ extern int _zz_ready; extern int _zz_hasdebug; -extern int _zz_seed; extern float _zz_ratio; +extern int _zz_seed; +extern int _zz_signal; /* Library initialisation shit */ extern void _zz_init(void) __attribute__((constructor)); diff --git a/src/load-signal.c b/src/load-signal.c new file mode 100644 index 0000000..75ba8f7 --- /dev/null +++ b/src/load-signal.c @@ -0,0 +1,125 @@ +/* + * zzuf - general purpose fuzzer + * Copyright (c) 2006 Sam Hocevar + * All Rights Reserved + * + * $Id$ + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +/* + * load-signal.c: loaded signal functions + */ + +#include "config.h" + +/* needed for sighandler_t */ +#define _GNU_SOURCE + +#if defined HAVE_STDINT_H +# include +#elif defined HAVE_INTTYPES_H +# include +#endif +#include +#include + +#include +#include + +#include "libzzuf.h" +#include "debug.h" +#include "fuzz.h" +#include "load.h" + +/* Library functions that we divert */ +static sighandler_t (*signal_orig) (int signum, sighandler_t handler); +static int (*sigaction_orig) (int signum, const struct sigaction *act, + struct sigaction *oldact); +/* Local functions */ +static int isfatal(int signum); + +void _zz_load_signal(void) +{ + LOADSYM(signal); + LOADSYM(sigaction); +} + +static int isfatal(int signum) +{ + switch(signum) + { + case SIGABRT: + case SIGFPE: + case SIGILL: + case SIGQUIT: + case SIGSEGV: + case SIGTRAP: +#ifdef SIGSYS + case SIGSYS: +#endif +#ifdef SIGEMT + case SIGEMT: +#endif +#ifdef SIGBUS + case SIGBUS: +#endif +#ifdef SIGXCPU + case SIGXCPU: +#endif +#ifdef SIGXFSZ + case SIGXFSZ: +#endif + return 1; + default: + return 0; + } +} + +sighandler_t signal(int signum, sighandler_t handler) +{ + sighandler_t ret; + + if(!_zz_ready) + LOADSYM(signal); + + if(!_zz_signal) + return signal_orig(signum, handler); + + ret = signal_orig(signum, isfatal(signum) ? SIG_DFL : handler); + + debug("signal(%i, %p) = %p", signum, handler, ret); + + return ret; +} + +int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) +{ + int ret; + + if(!_zz_ready) + LOADSYM(sigaction); + + if(!_zz_signal) + return sigaction_orig(signum, act, oldact); + + if(act && isfatal(signum)) + { + struct sigaction newact; + memcpy(&newact, act, sizeof(struct sigaction)); + newact.sa_handler = SIG_DFL; + ret = sigaction_orig(signum, &newact, oldact); + } + else + ret = sigaction_orig(signum, act, oldact); + + debug("sigaction(%i, %p, %p) = %i", signum, act, oldact, ret); + + return ret; +} + diff --git a/src/load.h b/src/load.h index fe50f31..503e243 100644 --- a/src/load.h +++ b/src/load.h @@ -27,5 +27,6 @@ } while(0) extern void _zz_load_fd(void); +extern void _zz_load_signal(void); extern void _zz_load_stream(void); diff --git a/src/zzuf.c b/src/zzuf.c index 9e1802d..b512da3 100644 --- a/src/zzuf.c +++ b/src/zzuf.c @@ -96,25 +96,26 @@ int main(int argc, char *argv[]) static struct option long_options[] = { /* Long option, needs arg, flag, short option */ - { "include", 1, NULL, 'I' }, - { "exclude", 1, NULL, 'E' }, - { "cmdline", 0, NULL, 'c' }, - { "stdin", 0, NULL, 'i' }, - { "seed", 1, NULL, 's' }, - { "ratio", 1, NULL, 'r' }, - { "fork", 1, NULL, 'F' }, { "max-bytes", 1, NULL, 'B' }, - { "max-time", 1, NULL, 'T' }, - { "quiet", 0, NULL, 'q' }, + { "cmdline", 0, NULL, 'c' }, { "debug", 0, NULL, 'd' }, + { "exclude", 1, NULL, 'E' }, + { "fork", 1, NULL, 'F' }, { "help", 0, NULL, 'h' }, + { "stdin", 0, NULL, 'i' }, + { "include", 1, NULL, 'I' }, + { "quiet", 0, NULL, 'q' }, + { "ratio", 1, NULL, 'r' }, + { "seed", 1, NULL, 's' }, + { "signal", 0, NULL, 'S' }, + { "max-time", 1, NULL, 'T' }, { "version", 0, NULL, 'v' }, }; - int c = getopt_long(argc, argv, "B:cdE:F:hiI:qr:s:T:v", + int c = getopt_long(argc, argv, "B:cdE:F:hiI:qr:s:ST:v", long_options, &option_index); # else # define MOREINFO "Try `%s -h' for more information.\n" - int c = getopt(argc, argv, "B:cdE:F:hiI:qr:s:T:v"); + int c = getopt(argc, argv, "B:cdE:F:hiI:qr:s:ST:v"); # endif if(c == -1) break; @@ -163,6 +164,9 @@ int main(int argc, char *argv[]) case 'q': /* --quiet */ quiet = 1; break; + case 'S': /* --signal */ + setenv("ZZUF_SIGNAL", "1", 1); + break; case 'd': /* --debug */ setenv("ZZUF_DEBUG", "1", 1); break; @@ -528,6 +532,7 @@ static void usage(void) printf(" -r, --ratio bit fuzzing ratio (default 0.004)\n"); printf(" -s, --seed random seed (default 0)\n"); printf(" --seed specify a seed range\n"); + printf(" -S, --signal prevent children from diverting crashing signals\n"); printf(" -T, --max-time kill children that run for more than seconds\n"); printf(" -v, --version output version information and exit\n"); # else @@ -543,6 +548,7 @@ static void usage(void) printf(" -r bit fuzzing ratio (default 0.004)\n"); printf(" -s random seed (default 0)\n"); printf(" specify a seed range\n"); + printf(" -S prevent children from diverting crashing signals\n"); printf(" -T kill children that run for more than seconds\n"); printf(" -v output version information and exit\n"); # endif