From aa1dc921930d63278b859d5cadbb6a161c5efb10 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Sun, 14 Jan 2007 23:41:03 +0000 Subject: [PATCH] * Support ranges with the -r flag. --- configure.ac | 2 + doc/zzuf.1 | 29 +++++++---- src/Makefile.am | 3 +- src/fd.c | 40 ++++++++++++--- src/fd.h | 3 +- src/libzzuf.c | 9 ++-- src/zzuf.c | 131 ++++++++++++++++++++++++++---------------------- 7 files changed, 134 insertions(+), 83 deletions(-) diff --git a/configure.ac b/configure.ac index 8dc92a6..e6bee79 100644 --- a/configure.ac +++ b/configure.ac @@ -32,6 +32,8 @@ AC_CHECK_FUNCS(getopt_long, GETOPT_LIBS="${GETOPT_LIBS} -lgnugetopt"])]) AC_SUBST(GETOPT_LIBS) +AC_CHECK_LIB(m, log, [MATH_LIBS="-lm"]) +AC_SUBST(MATH_LIBS) AC_CHECK_LIB(dl, dlopen, [DL_LIBS="-ldl"]) AC_SUBST(DL_LIBS) diff --git a/doc/zzuf.1 b/doc/zzuf.1 index 8fa7055..5ce9091 100644 --- a/doc/zzuf.1 +++ b/doc/zzuf.1 @@ -2,7 +2,7 @@ .SH NAME zzuf \- multiple purpose fuzzer .SH SYNOPSIS -\fBzzuf\fR [\fB\-AcdiMnqSvx\fR] [\fB\-r\fR \fIratio\fR] [\fB\-s\fR \fIseed\fR|\fB\-s\fR \fIstart:stop\fR] +\fBzzuf\fR [\fB\-AcdiMnqSvx\fR] [\fB\-s\fR \fIseed\fR|\fB\-s\fR \fIstart:stop\fR] [\fB\-r\fR \fIratio\fR|\fB\-r\fR \fIstart:stop\fR] .br [\fB\-D\fR \fIdelay\fR] [\fB\-F\fR \fIforks\fR] [\fB\-C\fR \fIcrashes\fR] [\fB\-B\fR \fIbytes\fR] .br @@ -40,8 +40,8 @@ if the \fBcat\fR utility had been called: .TP \fB\-A\fR, \fB\-\-autoinc\fR Increment random seed each time a new file is opened. This is only required -if the same application is expected to open the same file several times and -you want to test a different seed each time. +if one instance of the application is expected to open the same file several +times and you want to test a different seed each time. .TP \fB\-B\fR, \fB\-\-max\-bytes\fR=\fIn\fR Automatically terminate child processes that output more than \fIn\fR bytes @@ -165,11 +165,19 @@ is very verbose but only its exit code or signaled status is really useful to you. .TP \fB\-r\fR, \fB\-\-ratio\fR=\fIratio\fR +.PD 0 +.TP +\fB\-r\fR, \fB\-\-ratio\fR=\fIstart:stop\fR +.PD Specify the proportion of bits that will be randomly fuzzed. A value of 0 will not fuzz anything. A value of 0.05 will fuzz 5% of the open files' bits. A value of 1.0 or more will fuzz all the bytes, theoretically making the input files undiscernible from random data. The default fuzzing ratio is 0.004 (fuzz 0.4% of the files' bits). + +An interval can be specified. When doing so, \fBzzuf\fR will pick ratio +values from the interval. This is only meaningful if an interval is also +specified with the \fB\-s\fR flag. .TP \fB\-R\fR, \fB\-\-refuse\fR=\fIlist\fR Refuse a list of characters by not fuzzing bytes that would otherwise be @@ -258,14 +266,15 @@ can be read by \fBVLC\fR to reproduce the same behaviour without using .br \fB vlc fuzzy\-movie.avi\fR .PP -Fuzz 2% of \fBMPlayer\fR's input bits (\fB\-r\ 0.02\fR) with seeds 0 to 9999 -(\fB\-s\ 0:10000\fR), disabling its standard output messages (\fB\-q\fR), -launching up to five simultaneous child processes (\fB\-F\ 5\fR) but wait at -least half a second between launches (\fB\-D\ 0.5\fR), killing \fBMPlayer\fR -if it takes more than one minute to read the file (\fB\-T\ 60\fR) and -disabling its \fBSIGSEGV\fR signal handler (\fB\-S\fR): +Fuzz between 0.1% and 2% of \fBMPlayer\fR's input bits (\fB\-r\ 0.001:0.02\fR) +with seeds 0 to 9999 (\fB\-s\ 0:10000\fR), disabling its standard output +messages (\fB\-q\fR), launching up to five simultaneous child processes +(\fB\-F\ 5\fR) but wait at least half a second between launches +(\fB\-D\ 0.5\fR), killing \fBMPlayer\fR if it takes more than one minute to +read the file (\fB\-T\ 60\fR) and disabling its \fBSIGSEGV\fR signal handler +(\fB\-S\fR): .PP -\fB zzuf \-c \-r 0.02 \-q \-s 0:10000 \-F 5 \-D 0.5 \-T 60 \-S \\\fR +\fB zzuf \-c \-r 0.001:0.02 \-q \-s 0:10000 \-F 5 \-D 0.5 \-T 60 \-S \\\fR .br \fB mplayer \-\- \-benchmark \-vo null \-fps 1000 movie.avi\fR .PP diff --git a/src/Makefile.am b/src/Makefile.am index 78bf61b..f6d7fdd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,10 +5,11 @@ COMMON = random.c random.h fd.c fd.h fuzz.c fuzz.h bin_PROGRAMS = zzuf zzuf_SOURCES = zzuf.c $(COMMON) md5.c md5.h timer.c timer.h zzuf_CFLAGS = -DLIBDIR=\"$(libdir)/zzuf\" +zzuf_LDFLAGS = @MATH_LIBS@ pkglib_LTLIBRARIES = libzzuf.la libzzuf_la_SOURCES = libzzuf.c libzzuf.h $(COMMON) debug.c debug.h \ load-fd.c load-mem.c load-signal.c load-stream.c load.h libzzuf_la_LDFLAGS = -avoid-version -no-undefined -libzzuf_la_LIBADD = @GETOPT_LIBS@ @DL_LIBS@ +libzzuf_la_LIBADD = @GETOPT_LIBS@ @DL_LIBS@ @MATH_LIBS@ diff --git a/src/fd.c b/src/fd.c index 4476855..bb17d52 100644 --- a/src/fd.c +++ b/src/fd.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "debug.h" #include "libzzuf.h" @@ -54,7 +55,8 @@ static int *fds, static_fds[STATIC_FILES]; static int maxfd, nfiles; static int32_t seed = DEFAULT_SEED; -static double ratio = DEFAULT_RATIO; +static double minratio = DEFAULT_RATIO; +static double maxratio = DEFAULT_RATIO; static int autoinc = 0; void _zz_include(char const *regex) @@ -74,13 +76,35 @@ void _zz_setseed(int32_t s) seed = s; } -void _zz_setratio(double r) +void _zz_setratio(double r0, double r1) { - if(r < MIN_RATIO) - r = MIN_RATIO; - else if(r > MAX_RATIO) - r = MAX_RATIO; - ratio = r; + minratio = r0 < MIN_RATIO ? MIN_RATIO : r0 > MAX_RATIO ? MAX_RATIO : r0; + maxratio = r1 < MIN_RATIO ? MIN_RATIO : r1 > MAX_RATIO ? MAX_RATIO : r1; + if(maxratio < minratio) + maxratio = minratio; +} + +double _zz_getratio(void) +{ + uint8_t const shuffle[16] = + { 0, 12, 2, 10, + 14, 8, 15, 7, + 9, 13, 3, 6, + 4, 1, 11, 5 }; + uint16_t rate; + double min, max, cur; + + rate = shuffle[seed & 0xf] << 12; + rate |= (seed & 0xf0) << 4; + rate |= (seed & 0xf00) >> 4; + rate |= (seed & 0xf000) >> 12; + + min = log(minratio); + max = log(maxratio); + + cur = min + (max - min) * rate / 0xffff; + + return exp(cur); } void _zz_setautoinc(void) @@ -188,7 +212,7 @@ void _zz_register(int fd) files[i].managed = 1; files[i].pos = 0; files[i].fuzz.seed = seed; - files[i].fuzz.ratio = ratio; + files[i].fuzz.ratio = _zz_getratio(); files[i].fuzz.cur = -1; #ifdef HAVE_FGETLN files[i].fuzz.tmp = NULL; diff --git a/src/fd.h b/src/fd.h index f5e9341..5124372 100644 --- a/src/fd.h +++ b/src/fd.h @@ -19,7 +19,8 @@ extern void _zz_include(char const *); extern void _zz_exclude(char const *); extern void _zz_setseed(int32_t); -extern void _zz_setratio(double); +extern void _zz_setratio(double, double); +extern double _zz_getratio(void); extern void _zz_setautoinc(void); extern void _zz_fd_init(void); extern void _zz_fd_fini(void); diff --git a/src/libzzuf.c b/src/libzzuf.c index 9c77bcb..f0b8681 100644 --- a/src/libzzuf.c +++ b/src/libzzuf.c @@ -51,7 +51,7 @@ int _zz_network = 0; /* Library initialisation shit */ void _zz_init(void) { - char *tmp; + char *tmp, *tmp2; _zz_load_mem(); _zz_load_signal(); @@ -66,9 +66,10 @@ void _zz_init(void) if(tmp && *tmp) _zz_setseed(atol(tmp)); - tmp = getenv("ZZUF_RATIO"); - if(tmp && *tmp) - _zz_setratio(atof(tmp)); + tmp = getenv("ZZUF_MINRATIO"); + tmp2 = getenv("ZZUF_MAXRATIO"); + if(tmp && *tmp && tmp2 && *tmp2) + _zz_setratio(atof(tmp), atof(tmp2)); tmp = getenv("ZZUF_AUTOINC"); if(tmp && *tmp == '1') diff --git a/src/zzuf.c b/src/zzuf.c index 9c78871..f461cb5 100644 --- a/src/zzuf.c +++ b/src/zzuf.c @@ -73,6 +73,7 @@ static struct child_list pid_t pid; int fd[3]; /* 0 is debug, 1 is stderr, 2 is stdout */ int bytes, seed; + double ratio; int64_t date; struct md5 *ctx; } *child_list; @@ -82,8 +83,8 @@ static char **newargv; static char *protect = NULL, *refuse = NULL; static uint32_t seed = DEFAULT_SEED; static uint32_t endseed = DEFAULT_SEED + 1; -static double ratio = DEFAULT_RATIO; -static double endratio = DEFAULT_RATIO; +static double minratio = DEFAULT_RATIO; +static double maxratio = DEFAULT_RATIO; static int quiet = 0; static int maxbytes = -1; static int md5 = 0; @@ -217,8 +218,8 @@ int main(int argc, char *argv[]) break; case 'r': /* --ratio */ parser = strchr(optarg, ':'); - ratio = atof(optarg); - endratio = parser ? atof(parser + 1) : ratio; + minratio = atof(optarg); + maxratio = parser ? atof(parser + 1) : minratio; break; case 'R': /* --refuse */ refuse = optarg; @@ -257,6 +258,9 @@ int main(int argc, char *argv[]) int optind = 1; #endif + _zz_setratio(minratio, maxratio); + _zz_setseed(seed); + /* If asked to read from the standard input */ if(optind >= argc) { @@ -268,9 +272,6 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - _zz_setseed(seed); - _zz_setratio(ratio); - loop_stdin(); return EXIT_SUCCESS; @@ -380,9 +381,9 @@ static void loop_stdin(void) if(md5) { _zz_md5_fini(md5sum, ctx); - fprintf(stderr, "zzuf[seed=%i]: %.02x%.02x%.02x%.02x%.02x%.02x" - "%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x\n", - seed, md5sum[0], md5sum[1], md5sum[2], md5sum[3], + fprintf(stderr, "zzuf[s=%i,r=%g]: %.02x%.02x%.02x%.02x%.02x" + "%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x\n", + seed, minratio, md5sum[0], md5sum[1], md5sum[2], md5sum[3], md5sum[4], md5sum[5], md5sum[6], md5sum[7], md5sum[8], md5sum[9], md5sum[10], md5sum[11], md5sum[12], md5sum[13], md5sum[14], md5sum[15]); @@ -506,8 +507,10 @@ static void spawn_children(void) /* Set environment variables */ sprintf(buf, "%i", seed); setenv("ZZUF_SEED", buf, 1); - sprintf(buf, "%g", ratio); - setenv("ZZUF_RATIO", buf, 1); + sprintf(buf, "%g", minratio); + setenv("ZZUF_MINRATIO", buf, 1); + sprintf(buf, "%g", maxratio); + setenv("ZZUF_MAXRATIO", buf, 1); /* Run our process */ if(execvp(newargv[0], newargv)) @@ -518,9 +521,6 @@ static void spawn_children(void) return; } - if(verbose) - fprintf(stderr, "zzuf[seed=%i]: launched %s\n", seed, newargv[0]); - /* We’re the parent, acknowledge spawn */ child_list[i].date = now; child_list[i].pid = pid; @@ -531,13 +531,20 @@ static void spawn_children(void) } child_list[i].bytes = 0; child_list[i].seed = seed; + child_list[i].ratio = _zz_getratio(); child_list[i].status = STATUS_RUNNING; if(md5) child_list[i].ctx = _zz_md5_init(); + if(verbose) + fprintf(stderr, "zzuf[s=%i,r=%g]: launched %s\n", + child_list[i].seed, child_list[i].ratio, newargv[0]); + lastlaunch = now; child_count++; seed++; + + _zz_setseed(seed); } static void clean_children(void) @@ -552,8 +559,9 @@ static void clean_children(void) && maxbytes >= 0 && child_list[i].bytes > maxbytes) { if(verbose) - fprintf(stderr, "zzuf[seed=%i]: data output exceeded," - " sending SIGTERM\n", child_list[i].seed); + fprintf(stderr, "zzuf[s=%i,r=%g]: " + "data output exceeded, sending SIGTERM\n", + child_list[i].seed, child_list[i].ratio); kill(child_list[i].pid, SIGTERM); child_list[i].date = now; child_list[i].status = STATUS_SIGTERM; @@ -564,8 +572,9 @@ static void clean_children(void) && now > child_list[i].date + maxtime) { if(verbose) - fprintf(stderr, "zzuf[seed=%i]: running time exceeded," - " sending SIGTERM\n", child_list[i].seed); + fprintf(stderr, "zzuf[s=%i,r=%g]: " + "running time exceeded, sending SIGTERM\n", + child_list[i].seed, child_list[i].ratio); kill(child_list[i].pid, SIGTERM); child_list[i].date = now; child_list[i].status = STATUS_SIGTERM; @@ -579,8 +588,9 @@ static void clean_children(void) && now > child_list[i].date + 2000000) { if(verbose) - fprintf(stderr, "zzuf[seed=%i]: not responding," - " sending SIGKILL\n", child_list[i].seed); + fprintf(stderr, "zzuf[s=%i,r=%g]: " + "not responding, sending SIGKILL\n", + child_list[i].seed, child_list[i].ratio); kill(child_list[i].pid, SIGKILL); child_list[i].status = STATUS_SIGKILL; } @@ -604,17 +614,18 @@ static void clean_children(void) if(checkexit && WIFEXITED(status) && WEXITSTATUS(status)) { - fprintf(stderr, "zzuf[seed=%i]: exit %i\n", - child_list[i].seed, WEXITSTATUS(status)); + fprintf(stderr, "zzuf[s=%i,r=%g]: exit %i\n", + child_list[i].seed, child_list[i].ratio, + WEXITSTATUS(status)); crashes++; } else if(WIFSIGNALED(status) && !(WTERMSIG(status) == SIGTERM && child_list[i].status == STATUS_SIGTERM)) { - fprintf(stderr, "zzuf[seed=%i]: signal %i%s%s\n", - child_list[i].seed, WTERMSIG(status), - sig2str(WTERMSIG(status)), + fprintf(stderr, "zzuf[s=%i,r=%g]: signal %i%s%s\n", + child_list[i].seed, child_list[i].ratio, + WTERMSIG(status), sig2str(WTERMSIG(status)), (WTERMSIG(status) == SIGKILL && maxmem >= 0) ? " (memory exceeded?)" : ""); crashes++; @@ -627,12 +638,12 @@ static void clean_children(void) if(md5) { _zz_md5_fini(md5sum, child_list[i].ctx); - fprintf(stderr, "zzuf[seed=%i]: %.02x%.02x%.02x%.02x%.02x%.02x" - "%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x\n", - child_list[i].seed, md5sum[0], md5sum[1], md5sum[2], - md5sum[3], md5sum[4], md5sum[5], md5sum[6], md5sum[7], - md5sum[8], md5sum[9], md5sum[10], md5sum[11], md5sum[12], - md5sum[13], md5sum[14], md5sum[15]); + fprintf(stderr, "zzuf[s=%i,r=%g]: %.02x%.02x%.02x%.02x%.02x" + "%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x\n", + child_list[i].seed, child_list[i].ratio, md5sum[0], + md5sum[1], md5sum[2], md5sum[3], md5sum[4], md5sum[5], + md5sum[6], md5sum[7], md5sum[8], md5sum[9], md5sum[10], + md5sum[11], md5sum[12], md5sum[13], md5sum[14], md5sum[15]); } child_list[i].status = STATUS_FREE; child_count--; @@ -794,31 +805,32 @@ static void usage(void) printf("\n"); printf("Mandatory arguments to long options are mandatory for short options too.\n"); # ifdef HAVE_GETOPT_LONG - printf(" -A, --autoinc increment seed each time a new file is opened\n"); - printf(" -B, --max-bytes kill children that output more than bytes\n"); - printf(" -c, --cmdline only fuzz files specified in the command line\n"); - printf(" -C, --max-crashes stop after children have crashed (default 1)\n"); - printf(" -d, --debug print debug messages\n"); - printf(" -D, --delay delay between forks\n"); - printf(" -E, --exclude do not fuzz files matching \n"); - printf(" -F, --max-forks number of concurrent children (default 1)\n"); - printf(" -i, --stdin fuzz standard input\n"); - printf(" -I, --include only fuzz files matching \n"); - printf(" -m, --md5 compute the output's MD5 hash\n"); - printf(" -M, --max-memory maximum child virtual memory size in MB\n"); - printf(" -n, --network fuzz network input\n"); - printf(" -P, --protect protect bytes and characters in \n"); - printf(" -q, --quiet do not print children's messages\n"); - printf(" -r, --ratio bit fuzzing ratio (default 0.004)\n"); - printf(" -R, --refuse refuse bytes and characters in \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, --verbose print information during the run\n"); - printf(" -x, --check-exit report processes that exit with a non-zero status\n"); - printf(" -h, --help display this help and exit\n"); - printf(" -V, --version output version information and exit\n"); + printf(" -A, --autoinc increment seed each time a new file is opened\n"); + printf(" -B, --max-bytes kill children that output more than bytes\n"); + printf(" -c, --cmdline only fuzz files specified in the command line\n"); + printf(" -C, --max-crashes stop after children have crashed (default 1)\n"); + printf(" -d, --debug print debug messages\n"); + printf(" -D, --delay delay between forks\n"); + printf(" -E, --exclude do not fuzz files matching \n"); + printf(" -F, --max-forks number of concurrent children (default 1)\n"); + printf(" -i, --stdin fuzz standard input\n"); + printf(" -I, --include only fuzz files matching \n"); + printf(" -m, --md5 compute the output's MD5 hash\n"); + printf(" -M, --max-memory maximum child virtual memory size in MB\n"); + printf(" -n, --network fuzz network input\n"); + printf(" -P, --protect protect bytes and characters in \n"); + printf(" -q, --quiet do not print children's messages\n"); + printf(" -r, --ratio bit fuzzing ratio (default %g)\n", DEFAULT_RATIO); + printf(" --ratio specify a ratio range\n"); + printf(" -R, --refuse refuse bytes and characters in \n"); + printf(" -s, --seed random seed (default %i)\n", DEFAULT_SEED); + 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, --verbose print information during the run\n"); + printf(" -x, --check-exit report processes that exit with a non-zero status\n"); + printf(" -h, --help display this help and exit\n"); + printf(" -V, --version output version information and exit\n"); # else printf(" -A increment seed each time a new file is opened\n"); printf(" -B kill children that output more than bytes\n"); @@ -835,9 +847,10 @@ static void usage(void) printf(" -n fuzz network input\n"); printf(" -P protect bytes and characters in \n"); printf(" -q do not print the fuzzed application's messages\n"); - printf(" -r bit fuzzing ratio (default 0.004)\n"); + printf(" -r bit fuzzing ratio (default %g)\n", DEFAULT_RATIO); + printf(" specify a ratio range\n"); printf(" -R refuse bytes and characters in \n"); - printf(" -s random seed (default 0)\n"); + printf(" -s random seed (default %i)\n", DEFAULT_SEED); 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");