* Implemented -b/--bytes to restrict fuzzing to specific offsets.
This commit is contained in:
parent
8830524877
commit
68446780ce
46
doc/zzuf.1
46
doc/zzuf.1
@ -2,13 +2,13 @@
|
||||
.SH NAME
|
||||
zzuf \- multiple purpose fuzzer
|
||||
.SH SYNOPSIS
|
||||
\fBzzuf\fR [\fB\-AcdiMnqSvx\fR] [\fB\-s\fR \fIseed\fR|\fB\-s\fR \fIstart:stop\fR] [\fB\-r\fR \fIratio\fR|\fB\-r\fR \fImin:max\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 \fImin:max\fR]
|
||||
.br
|
||||
[\fB\-D\fR \fIdelay\fR] [\fB\-F\fR \fIforks\fR] [\fB\-C\fR \fIcrashes\fR] [\fB\-B\fR \fIbytes\fR]
|
||||
[\fB\-D\fR \fIdelay\fR] [\fB\-F\fR \fIforks\fR] [\fB\-C\fR \fIcrashes\fR] [\fB\-B\fR \fIbytes\fR] [\fB\-T\fR \fIseconds\fR]
|
||||
.br
|
||||
[\fB\-T\fR \fIseconds\fR] [\fB\-M\fR \fImegabytes\fR] [\fB\-P\fR \fIprotect\fR] [\fB\-R\fR \fIrefuse\fR]
|
||||
[\fB\-M\fR \fImegabytes\fR] [\fB\-b\fR \fIranges\fR] [\fB\-P\fR \fIprotect\fR] [\fB\-R\fR \fIrefuse\fR]
|
||||
.br
|
||||
[\fB\-I\fR \fIinclude\fR] [\fB\-E\fR \fIexclude\fR] [\fIPROGRAM\fR [\fB\-\-\fR] [\fIARGS\fR]...]
|
||||
[\fB\-I\fR \fIinclude\fR] [\fB\-E\fR \fIexclude\fR] [\fIPROGRAM\fR [\fB\-\-\fR] [\fIARGS\fR]...]
|
||||
.br
|
||||
\fBzzuf \-h\fR | \fB\-\-help\fR
|
||||
.br
|
||||
@ -43,6 +43,17 @@ Increment random seed each time a new file is opened. This is only required
|
||||
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\-\-bytes\fR=\fIranges\fR
|
||||
Restrict fuzzing to bytes whose offsets in the file are within \fIranges\fR.
|
||||
|
||||
Range values start at zero and are inclusive. Use dashes between range values
|
||||
and commas between ranges. If the right-hand part of a range is ommited, it
|
||||
means end of file. For instance, to restrict fuzzing to bytes 0, 3, 4, 5 and
|
||||
all bytes after offset 31, use \(oq\fB\-r0,3-5,31-\fR\(cq.
|
||||
|
||||
This option is useful to preserve file headers or corrupt only a specific
|
||||
portion of a file.
|
||||
.TP
|
||||
\fB\-B\fR, \fB\-\-max\-bytes\fR=\fIn\fR
|
||||
Automatically terminate child processes that output more than \fIn\fR bytes
|
||||
on the standard output and standard error channels. This is useful to detect
|
||||
@ -149,12 +160,12 @@ backslash (\(oq\\\(cq)
|
||||
.RE
|
||||
.IP
|
||||
You can use \(oq\fB\-\fR\(cq to specify ranges. For instance, to protect all
|
||||
bytes from \(oq\\001\(cq to \(oq/\(cq, use \(oq\fB\-P\ \(dq\\001\-/\(dq\fR\(cq.
|
||||
bytes from \(oq\\001\(cq to \(oq/\(cq, use \(oq\fB\-P\ \(aq\\001\-/\(aq\fR\(cq.
|
||||
|
||||
The statistical outcome of this option should not be overlooked: if characters
|
||||
are protected, the effect of the \(oq\fB\-r\fR\(cq flag will vary depending
|
||||
on the data being fuzzed. For instance, asking to fuzz 1% of input bits
|
||||
(\fB\-r\ 0.01\fR) and to protect lowercase characters (\fB\-P\ a\-z\fR) will
|
||||
(\fB\-r0.01\fR) and to protect lowercase characters (\fB\-P\ a\-z\fR) will
|
||||
result in an actual average fuzzing ratio of 0.9% with truly random data,
|
||||
0.3% with random ASCII data and 0.2% with standard English text.
|
||||
|
||||
@ -241,7 +252,7 @@ Fuzz the input of the \fBcat\fR program using default settings:
|
||||
.PP
|
||||
Fuzz 1% of the input bits of the \fBcat\fR program using seed 94324:
|
||||
.PP
|
||||
\fB zzuf \-s 94324 \-r 0.01 cat /etc/motd\fR
|
||||
\fB zzuf \-s94324 \-r0.01 cat /etc/motd\fR
|
||||
.PP
|
||||
Fuzz the input of the \fBcat\fR program but do not fuzz newline characters
|
||||
and prevent non-ASCII characters from appearing in the output:
|
||||
@ -261,21 +272,22 @@ and restricting fuzzing to filenames that appear on the command line
|
||||
can be read by VLC to reproduce the same behaviour without using
|
||||
\fBzzuf\fR:
|
||||
.PP
|
||||
\fB zzuf \-c \-s 87423 \-r 0.01 vlc movie.avi\fR
|
||||
\fB zzuf \-c \-s87423 \-r0.01 vlc movie.avi\fR
|
||||
.br
|
||||
\fB zzuf \-c \-s 87423 \-r 0.01 <movie.avi >fuzzy\-movie.avi\fR
|
||||
\fB zzuf \-c \-s87423 \-r0.01 <movie.avi >fuzzy\-movie.avi\fR
|
||||
.br
|
||||
\fB vlc fuzzy\-movie.avi\fR
|
||||
.PP
|
||||
Fuzz between 0.1% and 2% of MPlayer'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 MPlayer if it takes more than one minute to
|
||||
read the file (\fB\-T\ 60\fR) and disabling its \fBSIGSEGV\fR signal handler
|
||||
Fuzz between 0.1% and 2% of MPlayer's input bits (\fB\-r0.001:0.02\fR)
|
||||
with seeds 0 to 9999 (\fB\-s0:10000\fR), preserving the AVI 4-byte header
|
||||
by restricting fuzzing to offsets after 4 (\fB\-b4\-\fR), disabling its
|
||||
standard output messages (\fB\-q\fR), launching up to five simultaneous child
|
||||
processes (\fB\-F5\fR) but waiting at least half a second between launches
|
||||
(\fB\-D0.5\fR), killing MPlayer if it takes more than one minute to
|
||||
read the file (\fB\-T60\fR) and disabling its \fBSIGSEGV\fR signal handler
|
||||
(\fB\-S\fR):
|
||||
.PP
|
||||
\fB zzuf \-c \-r 0.001:0.02 \-q \-s 0:10000 \-F 5 \-D 0.5 \-T 60 \-S \\\fR
|
||||
\fB zzuf \-c \-r0.001:0.02 \-s0:10000 \-b4\- \-q \-F5 \-D0.5 \-T60 \-S \\\fR
|
||||
.br
|
||||
\fB mplayer \-\- \-benchmark \-vo null \-fps 1000 movie.avi\fR
|
||||
.PP
|
||||
@ -286,7 +298,7 @@ and open it in Firefox\(tm in auto-increment mode (\fB\-A\fR):
|
||||
.br
|
||||
(or: \fBjot -w \(aq<img src="hello.jpg#%d">\(aq 200 1 > hello.html\fR)
|
||||
.br
|
||||
\fB zzuf -A -I \(aqhello[.]jpg\(aq -r 0.001 firefox hello.html\fR
|
||||
\fB zzuf -A -I \(aqhello[.]jpg\(aq -r0.001 firefox hello.html\fR
|
||||
.SH RESTRICTIONS
|
||||
.PP
|
||||
Due to \fBzzuf\fR using shared object preloading (\fBLD_PRELOAD\fR,
|
||||
|
||||
59
src/fuzz.c
59
src/fuzz.c
@ -24,6 +24,7 @@
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libzzuf.h"
|
||||
@ -35,13 +36,52 @@
|
||||
#define MAGIC1 0x33ea84f7
|
||||
#define MAGIC2 0x783bc31f
|
||||
|
||||
/* Fuzzing variables */
|
||||
/* Per-offset byte protection */
|
||||
static unsigned int *ranges = NULL;
|
||||
static unsigned int ranges_static[512];
|
||||
|
||||
/* Per-value byte protection */
|
||||
static int protect[256];
|
||||
static int refuse[256];
|
||||
|
||||
/* Local prototypes */
|
||||
static void readchars(int *, char const *);
|
||||
|
||||
void _zz_bytes(char const *list)
|
||||
{
|
||||
char const *parser;
|
||||
unsigned int i, chunks;
|
||||
|
||||
/* Count commas */
|
||||
for(parser = list, chunks = 1; *parser; parser++)
|
||||
if(*parser == ',')
|
||||
chunks++;
|
||||
|
||||
/* TODO: free(ranges) if ranges != ranges_static */
|
||||
if(chunks >= 256)
|
||||
ranges = malloc((chunks + 1) * 2 * sizeof(unsigned int));
|
||||
else
|
||||
ranges = ranges_static;
|
||||
|
||||
/* Fill ranges list */
|
||||
for(parser = list, i = 0; i < chunks; i++)
|
||||
{
|
||||
char const *comma = strchr(parser, ',');
|
||||
char const *dash = strchr(parser, '-');
|
||||
|
||||
ranges[i * 2] = (dash == parser) ? 0 : atoi(parser);
|
||||
if(dash && (dash + 1 == comma || dash[1] == '\0'))
|
||||
ranges[i * 2 + 1] = ranges[i * 2]; /* special case */
|
||||
else if(dash && (!comma || dash < comma))
|
||||
ranges[i * 2 + 1] = atoi(dash + 1) + 1;
|
||||
else
|
||||
ranges[i * 2 + 1] = ranges[i * 2] + 1;
|
||||
parser = comma + 1;
|
||||
}
|
||||
|
||||
ranges[i * 2] = ranges[i * 2 + 1] = 0;
|
||||
}
|
||||
|
||||
void _zz_protect(char const *list)
|
||||
{
|
||||
readchars(protect, list);
|
||||
@ -65,8 +105,8 @@ void _zz_fuzz(int fd, volatile uint8_t *buf, uint64_t len)
|
||||
(unsigned long int)pos);
|
||||
#endif
|
||||
|
||||
fuzz = _zz_getfuzz(fd);
|
||||
aligned_buf = buf - pos;
|
||||
fuzz = _zz_getfuzz(fd);
|
||||
|
||||
for(i = pos / CHUNKBYTES;
|
||||
i < (pos + len + CHUNKBYTES - 1) / CHUNKBYTES;
|
||||
@ -102,7 +142,20 @@ void _zz_fuzz(int fd, volatile uint8_t *buf, uint64_t len)
|
||||
|
||||
for(j = start; j < stop; j++)
|
||||
{
|
||||
uint8_t byte = aligned_buf[j];
|
||||
unsigned int *r;
|
||||
uint8_t byte;
|
||||
|
||||
if(!ranges)
|
||||
goto range_ok;
|
||||
|
||||
for(r = ranges; r[1]; r += 2)
|
||||
if(j >= r[0] && (r[0] == r[1] || j < r[1]))
|
||||
goto range_ok;
|
||||
|
||||
continue; /* Not in a range */
|
||||
|
||||
range_ok:
|
||||
byte = aligned_buf[j];
|
||||
|
||||
if(protect[byte])
|
||||
continue;
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
* fuzz.h: fuzz functions
|
||||
*/
|
||||
|
||||
extern void _zz_bytes(char const *);
|
||||
extern void _zz_protect(char const *);
|
||||
extern void _zz_refuse(char const *);
|
||||
|
||||
|
||||
@ -78,6 +78,10 @@ void _zz_init(void)
|
||||
if(tmp && *tmp == '1')
|
||||
_zz_setautoinc();
|
||||
|
||||
tmp = getenv("ZZUF_BYTES");
|
||||
if(tmp && *tmp)
|
||||
_zz_bytes(tmp);
|
||||
|
||||
tmp = getenv("ZZUF_PROTECT");
|
||||
if(tmp && *tmp)
|
||||
_zz_protect(tmp);
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
|
||||
void _zz_opts_init(struct opts *opts)
|
||||
{
|
||||
opts->protect = opts->refuse = NULL;
|
||||
opts->bytes = opts->protect = opts->refuse = NULL;
|
||||
opts->seed = DEFAULT_SEED;
|
||||
opts->endseed = DEFAULT_SEED + 1;
|
||||
opts->minratio = opts->maxratio = DEFAULT_RATIO;
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
struct opts
|
||||
{
|
||||
char const **newargv;
|
||||
char *protect, *refuse;
|
||||
char *bytes, *protect, *refuse;
|
||||
uint32_t seed;
|
||||
uint32_t endseed;
|
||||
double minratio;
|
||||
|
||||
30
src/zzuf.c
30
src/zzuf.c
@ -125,9 +125,9 @@ int main(int argc, char *argv[])
|
||||
for(;;)
|
||||
{
|
||||
# if defined HAVE_REGEX_H
|
||||
# define OPTSTR "AB:cC:dD:E:F:iI:mM:nP:qr:R:s:ST:vxhV"
|
||||
# define OPTSTR "Ab:B:cC:dD:E:F:iI:mM:nP:qr:R:s:ST:vxhV"
|
||||
# else
|
||||
# define OPTSTR "AB:C:dD:F:imM:nP:qr:R:s:ST:vxhV"
|
||||
# define OPTSTR "Ab:B:C:dD:F:imM:nP:qr:R:s:ST:vxhV"
|
||||
# endif
|
||||
# if defined HAVE_GETOPT_LONG
|
||||
# define MOREINFO "Try `%s --help' for more information.\n"
|
||||
@ -136,6 +136,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
/* Long option, needs arg, flag, short option */
|
||||
{ "autoinc", 0, NULL, 'A' },
|
||||
{ "bytes", 1, NULL, 'b' },
|
||||
{ "max-bytes", 1, NULL, 'B' },
|
||||
#if defined HAVE_REGEX_H
|
||||
{ "cmdline", 0, NULL, 'c' },
|
||||
@ -180,6 +181,9 @@ int main(int argc, char *argv[])
|
||||
case 'A': /* --autoinc */
|
||||
setenv("ZZUF_AUTOINC", "1", 1);
|
||||
break;
|
||||
case 'b': /* --bytes */
|
||||
opts->bytes = optarg;
|
||||
break;
|
||||
case 'B': /* --max-bytes */
|
||||
opts->maxbytes = atoi(optarg);
|
||||
break;
|
||||
@ -296,6 +300,11 @@ int main(int argc, char *argv[])
|
||||
/* If asked to read from the standard input */
|
||||
if(optind >= argc)
|
||||
{
|
||||
if(opts->bytes)
|
||||
_zz_bytes(opts->bytes);
|
||||
|
||||
/* FIXME: protect and refuse are ignored */
|
||||
|
||||
if(opts->endseed != opts->seed + 1)
|
||||
{
|
||||
printf("%s: seed ranges are incompatible with stdin fuzzing\n",
|
||||
@ -334,6 +343,8 @@ int main(int argc, char *argv[])
|
||||
setenv("ZZUF_EXCLUDE", exclude, 1);
|
||||
#endif
|
||||
|
||||
if(opts->bytes)
|
||||
setenv("ZZUF_BYTES", opts->bytes, 1);
|
||||
if(opts->protect)
|
||||
setenv("ZZUF_PROTECT", opts->protect, 1);
|
||||
if(opts->refuse)
|
||||
@ -1020,14 +1031,15 @@ static void usage(void)
|
||||
{
|
||||
#if defined HAVE_REGEX_H
|
||||
printf("Usage: zzuf [-AcdimnqSvx] [-s seed|-s start:stop] [-r ratio|-r min:max]\n");
|
||||
printf(" [-D delay] [-F forks] [-C crashes] [-B bytes]\n");
|
||||
printf(" [-T seconds] [-M bytes] [-P protect] [-R refuse]\n");
|
||||
printf(" [-I include] [-E exclude] [PROGRAM [--] [ARGS]...]\n");
|
||||
#else
|
||||
printf("Usage: zzuf [-AdimnqSvx] [-s seed|-s start:stop] [-r ratio|-r min:max]\n");
|
||||
printf(" [-D delay] [-F forks] [-C crashes] [-B bytes]\n");
|
||||
printf(" [-T seconds] [-M bytes] [-P protect] [-R refuse]\n");
|
||||
printf(" [PROGRAM [--] [ARGS]...]\n");
|
||||
#endif
|
||||
printf(" [-D delay] [-F forks] [-C crashes] [-B bytes] [-T seconds]\n");
|
||||
printf(" [-M bytes] [-b ranges] [-P protect] [-R refuse]\n");
|
||||
#if defined HAVE_REGEX_H
|
||||
printf(" [-I include] [-E exclude] [PROGRAM [--] [ARGS]...]\n");
|
||||
#else
|
||||
printf(" [PROGRAM [--] [ARGS]...]\n");
|
||||
#endif
|
||||
# if defined HAVE_GETOPT_LONG
|
||||
printf(" zzuf -h | --help\n");
|
||||
@ -1041,6 +1053,7 @@ static void usage(void)
|
||||
printf("Mandatory arguments to long options are mandatory for short options too.\n");
|
||||
# if defined HAVE_GETOPT_LONG
|
||||
printf(" -A, --autoinc increment seed each time a new file is opened\n");
|
||||
printf(" -b, --bytes <ranges> only fuzz bytes at offsets within <ranges>\n");
|
||||
printf(" -B, --max-bytes <n> kill children that output more than <n> bytes\n");
|
||||
#if defined HAVE_REGEX_H
|
||||
printf(" -c, --cmdline only fuzz files specified in the command line\n");
|
||||
@ -1076,6 +1089,7 @@ static void usage(void)
|
||||
printf(" -V, --version output version information and exit\n");
|
||||
# else
|
||||
printf(" -A increment seed each time a new file is opened\n");
|
||||
printf(" -b <ranges> only fuzz bytes at offsets within <ranges>\n");
|
||||
printf(" -B <n> kill children that output more than <n> bytes\n");
|
||||
#if defined HAVE_REGEX_H
|
||||
printf(" -c only fuzz files specified in the command line\n");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user