diff --git a/doc/zzuf.1 b/doc/zzuf.1 index 49fd5c3..7700c8d 100644 --- a/doc/zzuf.1 +++ b/doc/zzuf.1 @@ -55,9 +55,6 @@ of the regular expressions will be ignored. Specify the number of simultaneous children that can be run. This option is only useful if the \fB\-s\fR flag is used with an interval argument. .TP -\fB\-h\fR, \fB\-\-help\fR -Display a short help message and exit. -.TP \fB\-i\fR, \fB\-\-stdin\fR Fuzz the application's standard input. By default \fBzzuf\fR only fuzzes files. .TP @@ -69,6 +66,36 @@ and you only want specific files to be fuzzed. Multiple \fB\-I\fR flags can be specified, in which case files matching any one of the regular expressions will be fuzzed. See also the \fB\-c\fR flag. .TP +\fB\-P\fR, \fB\-\-protect\fR=\fIlist\fR +Protect a list of characters so that if they appear in input data that would +normally be fuzzed, they are left unmodified instead. + +Characters in \fIlist\fR can be expressed verbatim or through escape sequences. +The sequences interpreted by \fBzzuf\fR are: +.RS +.TP +\fB\\n\fR +new line +.TP +\fB\\r\fR +return +.TP +\fB\\t\fR +tabulation +.TP +\fB\\0\fR +the null character +.TP +\fB\\x\fR\fINN\fR +the byte whose hexadecimal value is \fINN\fR +.TP +\fB\\\\\fR +backslash ('\\') +.RE +.IP +You can use '\fB-\fR' to specify ranges. For instance, to protect all bytes +from '\fB\\x01\fR' to ' ', use \fB\-P \(dq\\x01- \(dq\fR. +.TP \fB\-q\fR, \fB\-\-quiet\fR Hide the output of the fuzzed application. This is useful if the application is very verbose but only its exit code or signaled status is really useful to @@ -110,6 +137,9 @@ Automatically terminate child processes that run for more than \fIn\fR seconds. This is useful to detect infinite loops or processes stuck in other situations. See also the \fB\-B\fR flag. .TP +\fB\-h\fR, \fB\-\-help\fR +Display a short help message and exit. +.TP \fB\-v\fR, \fB\-\-version\fR Output version information and exit. .SH EXAMPLES @@ -179,6 +209,10 @@ all these complicated operations. They are planned, though. Due to \fBzzuf\fR using \fBLD_PRELOAD\fR 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 when run as an unprivileged user. +.PP +As of now, \fBzzuf\fR does not really support multithreaded applications. The +behaviour with multithreaded applications where more than one thread do file +descriptor operations is undefined. .SH AUTHOR .PP Copyright \(co 2006, 2007 Sam Hocevar . diff --git a/src/fuzz.c b/src/fuzz.c index d981653..1b2aa3b 100644 --- a/src/fuzz.c +++ b/src/fuzz.c @@ -42,8 +42,10 @@ void _zz_fuzz(int fd, uint8_t *buf, uint64_t len) unsigned long int pos = _zz_getpos(fd); unsigned int i, j, todo; +/* debug("fuzz(%i, %lli@%li)", fd, (unsigned long long int)len, (unsigned long int)pos); +*/ fuzz = _zz_getfuzz(fd); aligned_buf = buf - pos; @@ -68,9 +70,9 @@ void _zz_fuzz(int fd, uint8_t *buf, uint64_t len) while(todo--) { unsigned int idx = _zz_rand(CHUNKBYTES); - uint8_t byte = (1 << _zz_rand(8)); + uint8_t bit = (1 << _zz_rand(8)); - fuzz->data[idx] ^= byte; + fuzz->data[idx] ^= bit; } fuzz->cur = i; @@ -83,7 +85,12 @@ void _zz_fuzz(int fd, uint8_t *buf, uint64_t len) ? (i + 1) * CHUNKBYTES : pos + len; for(j = start; j < stop; j++) + { + if(_zz_protect[aligned_buf[j]]) + continue; + aligned_buf[j] ^= fuzz->data[j % CHUNKBYTES]; + } } } diff --git a/src/libzzuf.c b/src/libzzuf.c index cc024e4..52e2617 100644 --- a/src/libzzuf.c +++ b/src/libzzuf.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -45,11 +46,15 @@ float _zz_ratio = 0.004f; int _zz_seed = 0; int _zz_signal = 0; +/* Global tables */ +int _zz_protect[256]; + /* Local variables */ static regex_t * re_include = NULL; static regex_t * re_exclude = NULL; /* Local prototypes */ +static void _zz_protect_init(char const *); static void _zz_fd_init(void); static void _zz_fd_fini(void); @@ -74,6 +79,10 @@ void _zz_init(void) else if(_zz_ratio > 5.0f) _zz_ratio = 5.0f; + tmp = getenv("ZZUF_PROTECT"); + if(tmp && *tmp) + _zz_protect_init(tmp); + tmp = getenv("ZZUF_INCLUDE"); if(tmp && *tmp) { @@ -113,6 +122,67 @@ void _zz_fini(void) _zz_fd_fini(); } +/* Byte list stuff */ +static void _zz_protect_init(char const *list) +{ + static char const hex[] = "0123456789abcdef0123456789ABCDEF"; + char const *tmp; + int a, b; + + memset(_zz_protect, 0, 256 * sizeof(int)); + + for(tmp = list, a = b = -1; *tmp; tmp++) + { + int new; + + if(*tmp == '\\' && tmp[1] == '\0') + new = '\\'; + else if(*tmp == '\\') + { + tmp++; + if(*tmp == 'n') + new = '\n'; + else if(*tmp == 'r') + new = '\r'; + else if(*tmp == 't') + new = '\t'; + else if(*tmp == '0') + new = '\0'; + else if((*tmp == 'x' || *tmp == 'X') + && tmp[1] && strchr(hex, tmp[1]) + && tmp[2] && strchr(hex, tmp[2])) + { + new = ((strchr(hex, tmp[1]) - hex) & 0xf) << 4; + new |= (strchr(hex, tmp[2]) - hex) & 0xf; + tmp += 2; + } + else + new = (unsigned char)*tmp; /* XXX: OK for \\, but what else? */ + } + else + new = (unsigned char)*tmp; + + if(a != -1 && b == '-' && a <= new) + { + while(a <= new) + _zz_protect[a++] = 1; + a = b = -1; + } + else + { + if(a != -1) + _zz_protect[a] = 1; + a = b; + b = new; + } + } + + if(a != -1) + _zz_protect[a] = 1; + if(b != -1) + _zz_protect[b] = 1; +} + /* File descriptor stuff */ static struct files { diff --git a/src/libzzuf.h b/src/libzzuf.h index 6d3ab7d..41737ed 100644 --- a/src/libzzuf.h +++ b/src/libzzuf.h @@ -39,6 +39,9 @@ extern float _zz_ratio; extern int _zz_seed; extern int _zz_signal; +/* Internal tables */ +extern int _zz_protect[256]; + /* Library initialisation shit */ extern void _zz_init(void) __attribute__((constructor)); extern void _zz_fini(void) __attribute__((destructor)); diff --git a/src/zzuf.c b/src/zzuf.c index c094e78..1e458e3 100644 --- a/src/zzuf.c +++ b/src/zzuf.c @@ -110,6 +110,7 @@ int main(int argc, char *argv[]) { "help", 0, NULL, 'h' }, { "stdin", 0, NULL, 'i' }, { "include", 1, NULL, 'I' }, + { "protect", 1, NULL, 'P' }, { "quiet", 0, NULL, 'q' }, { "ratio", 1, NULL, 'r' }, { "seed", 1, NULL, 's' }, @@ -117,11 +118,11 @@ int main(int argc, char *argv[]) { "max-time", 1, NULL, 'T' }, { "version", 0, NULL, 'v' }, }; - int c = getopt_long(argc, argv, "B:cdE:F:hiI:qr:s:ST:v", + int c = getopt_long(argc, argv, "B:cdE:F:hiI:P: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:ST:v"); + int c = getopt(argc, argv, "B:cdE:F:hiI:P:qr:s:ST:v"); # endif if(c == -1) break; @@ -167,6 +168,9 @@ int main(int argc, char *argv[]) case 'T': /* --max-time */ maxtime = atof(optarg); break; + case 'P': /* --protect */ + setenv("ZZUF_PROTECT", optarg, 1); + break; case 'q': /* --quiet */ quiet = 1; break; @@ -541,9 +545,11 @@ static void version(void) #if defined(HAVE_GETOPT_H) static void usage(void) { - printf("Usage: zzuf [ -vqdhic ] [ -r ratio ] [ -s seed | -s start:stop ]\n"); - printf(" [ -F children ] [ -B bytes ] [ -T seconds ]\n"); - printf(" [ -I include ] [ -E exclude ] COMMAND [ARGS]...\n"); + printf("Usage: zzuf [ -qdic ] [ -r ratio ] [ -s seed | -s start:stop ]\n"); + printf(" [ -F children ] [ -B bytes ] [ -T seconds ] [ -P protect ]\n"); + printf(" [ -I include ] [ -E exclude ] COMMAND [ARGS]...\n"); + printf(" zzuf -h\n"); + printf(" zzuf -v\n"); printf("Run COMMAND and randomly fuzz its input.\n"); printf("\n"); printf("Mandatory arguments to long options are mandatory for short options too.\n"); @@ -553,15 +559,16 @@ static void usage(void) printf(" -d, --debug print debug messages\n"); printf(" -E, --exclude do not fuzz files matching \n"); printf(" -F, --fork number of concurrent children (default 1)\n"); - printf(" -h, --help display this help and exit\n"); printf(" -i, --stdin fuzz standard input\n"); printf(" -I, --include only fuzz files matching \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(" -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(" -h, --help display this help and exit\n"); printf(" -v, --version output version information and exit\n"); # else printf(" -B kill children that output more than bytes\n"); @@ -569,15 +576,16 @@ static void usage(void) printf(" -d print debug messages\n"); printf(" -E do not fuzz files matching \n"); printf(" -F number of concurrent forks (default 1)\n"); - printf(" -h display this help and exit\n"); printf(" -i fuzz standard input\n"); printf(" -I only fuzz files matching \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(" -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(" -h display this help and exit\n"); printf(" -v output version information and exit\n"); # endif printf("\n");