From c0aad3b6e578dc08f66102c40cc0863f66d908a1 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Sun, 7 Jan 2007 18:18:50 +0000 Subject: [PATCH] * If no argument is given, just fuzz standard input. --- src/Makefile.am | 6 +- src/chars.c | 96 +++++++++++++++++++ src/chars.h | 20 ++++ src/fd.c | 180 +++++++++++++++++++++++++++++++++++ src/fd.h | 33 +++++++ src/fuzz.c | 19 ++++ src/fuzz.h | 2 + src/libzzuf.c | 238 ++-------------------------------------------- src/libzzuf.h | 12 --- src/load-fd.c | 2 + src/load-signal.c | 1 + src/load-stream.c | 2 + src/zzuf.c | 61 ++++++++++-- 13 files changed, 418 insertions(+), 254 deletions(-) create mode 100644 src/chars.c create mode 100644 src/chars.h create mode 100644 src/fd.c create mode 100644 src/fd.h diff --git a/src/Makefile.am b/src/Makefile.am index ff75b31..4dafe90 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,12 +1,12 @@ bin_PROGRAMS = zzuf -zzuf_SOURCES = zzuf.c -AM_CPPFLAGS = -DLIBDIR=\"$(libdir)/zzuf\" +zzuf_SOURCES = zzuf.c random.c random.h chars.c chars.h fd.c fd.h fuzz.c fuzz.h +zzuf_CFLAGS = -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-signal.c load-stream.c load.h \ - random.c random.h + fd.c fd.h chars.c chars.h random.c random.h libzzuf_la_LDFLAGS = -avoid-version -no-undefined libzzuf_la_LIBADD = @GETOPT_LIBS@ @DL_LIBS@ diff --git a/src/chars.c b/src/chars.c new file mode 100644 index 0000000..4b5fcab --- /dev/null +++ b/src/chars.c @@ -0,0 +1,96 @@ +/* + * 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. + */ + +/* + * chars.c: protected/refused characters + */ + +#include "config.h" + +#if defined HAVE_STDINT_H +# include +#elif defined HAVE_INTTYPES_H +# include +#endif +#include + +#include "libzzuf.h" +#include "chars.h" + +void _zz_readchars(int *table, char const *list) +{ + static char const hex[] = "0123456789abcdef0123456789ABCDEF"; + char const *tmp; + int a, b; + + memset(table, 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] >= '0' && tmp[0] <= '7' && tmp[1] >= '0' + && tmp[1] <= '7' && tmp[2] >= '0' && tmp[2] <= '7') + { + new = tmp[2] - '0'; + new |= (int)(tmp[1] - '0') << 3; + new |= (int)(tmp[0] - '0') << 6; + tmp += 2; + } + 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) + table[a++] = 1; + a = b = -1; + } + else + { + if(a != -1) + table[a] = 1; + a = b; + b = new; + } + } + + if(a != -1) + table[a] = 1; + if(b != -1) + table[b] = 1; +} + diff --git a/src/chars.h b/src/chars.h new file mode 100644 index 0000000..6bc5396 --- /dev/null +++ b/src/chars.h @@ -0,0 +1,20 @@ +/* + * 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. + */ + +/* + * chars.h: character functions + */ + +extern void _zz_readchars(int *, char const *); + diff --git a/src/fd.c b/src/fd.c new file mode 100644 index 0000000..f77fc4f --- /dev/null +++ b/src/fd.c @@ -0,0 +1,180 @@ +/* + * 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. + */ + +/* + * libzzuf.c: preloaded wrapper library + */ + +#include "config.h" +#define _GNU_SOURCE + +#if defined HAVE_STDINT_H +# include +#elif defined HAVE_INTTYPES_H +# include +#endif +#include +#include + +#include "libzzuf.h" +#include "fd.h" + +regex_t * re_include = NULL; +regex_t * re_exclude = NULL; + +/* File descriptor stuff */ +static struct files +{ + int managed; + uint64_t seed; + uint64_t pos; + /* Public stuff */ + struct fuzz fuzz; +} +*files; +static int *fds; +static int maxfd, nfiles; + +void _zz_fd_init(void) +{ + files = NULL; + nfiles = 0; + + /* Start with one fd in the lookup table */ + fds = malloc(1 * sizeof(int)); + for(maxfd = 0; maxfd < 1; maxfd++) + fds[maxfd] = -1; +} + +void _zz_fd_fini(void) +{ + int i; + + for(i = 0; i < maxfd; i++) + { + if(!files[fds[i]].managed) + continue; + + /* XXX: What are we supposed to do? If filedescriptors weren't + * closed properly, there's a leak, but it's not our problem. */ + } + + free(files); + free(fds); +} + +int _zz_mustwatch(char const *file) +{ + if(re_include && regexec(re_include, file, 0, NULL, 0) == REG_NOMATCH) + return 0; /* not included: ignore */ + + if(re_exclude && regexec(re_exclude, file, 0, NULL, 0) != REG_NOMATCH) + return 0; /* excluded: ignore */ + + return 1; /* default */ +} + +int _zz_iswatched(int fd) +{ + if(fd < 0 || fd >= maxfd || fds[fd] == -1) + return 0; + + return 1; +} + +void _zz_register(int fd) +{ + int i; + + if(fd < 0 || fd > 65535 || (fd < maxfd && fds[fd] != -1)) + return; + + while(fd >= maxfd) + { + fds = realloc(fds, 2 * maxfd * sizeof(int)); + for(i = maxfd; i < maxfd * 2; i++) + fds[i] = -1; + maxfd *= 2; + } + + /* Find an empty slot */ + for(i = 0; i < nfiles; i++) + if(files[i].managed == 0) + break; + + /* No slot found, allocate memory */ + if(i == nfiles) + { + nfiles++; + files = realloc(files, nfiles * sizeof(struct files)); + } + + files[i].managed = 1; + files[i].pos = 0; + files[i].fuzz.cur = -1; + files[i].fuzz.data = malloc(CHUNKBYTES); +#ifdef HAVE_FGETLN + files[i].fuzz.tmp = NULL; +#endif + + fds[fd] = i; +} + +void _zz_unregister(int fd) +{ + if(fd < 0 || fd >= maxfd || fds[fd] == -1) + return; + + files[fds[fd]].managed = 0; + free(files[fds[fd]].fuzz.data); +#ifdef HAVE_FGETLN + if(files[fds[fd]].fuzz.tmp) + free(files[fds[fd]].fuzz.tmp); +#endif + + fds[fd] = -1; +} + +long int _zz_getpos(int fd) +{ + if(fd < 0 || fd >= maxfd || fds[fd] == -1) + return 0; + + return files[fds[fd]].pos; +} + +void _zz_setpos(int fd, long int pos) +{ + if(fd < 0 || fd >= maxfd || fds[fd] == -1) + return; + + files[fds[fd]].pos = pos; +} + +void _zz_addpos(int fd, long int off) +{ + if(fd < 0 || fd >= maxfd || fds[fd] == -1) + return; + + files[fds[fd]].pos += off; +} + +struct fuzz *_zz_getfuzz(int fd) +{ + if(fd < 0 || fd >= maxfd || fds[fd] == -1) + return NULL; + + return &files[fds[fd]].fuzz; +} + diff --git a/src/fd.h b/src/fd.h new file mode 100644 index 0000000..9cf5c9c --- /dev/null +++ b/src/fd.h @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/* + * fd.h: file descriptor functions + */ + +extern void _zz_fd_init(void); +extern void _zz_fd_fini(void); + +extern regex_t * re_include; +extern regex_t * re_exclude; + +extern int _zz_mustwatch(char const *); +extern int _zz_iswatched(int); +extern void _zz_register(int); +extern void _zz_unregister(int); +extern long int _zz_getpos(int); +extern void _zz_setpos(int, long int); +extern void _zz_addpos(int, long int); +extern struct fuzz *_zz_getfuzz(int); + diff --git a/src/fuzz.c b/src/fuzz.c index f63f2f3..ae84051 100644 --- a/src/fuzz.c +++ b/src/fuzz.c @@ -25,15 +25,34 @@ #endif #include #include +#include #include "libzzuf.h" #include "debug.h" #include "random.h" #include "fuzz.h" +#include "fd.h" #define MAGIC1 0x33ea84f7 #define MAGIC2 0x783bc31f +static float _zz_ratio = 0.004f; +static int _zz_seed = 0; + +void _zz_setseed(int seed) +{ + _zz_seed = seed; +} + +void _zz_setratio(float ratio) +{ + _zz_ratio = ratio; + if(_zz_ratio < 0.0f) + _zz_ratio = 0.0f; + else if(_zz_ratio > 5.0f) + _zz_ratio = 5.0f; +} + void _zz_fuzz(int fd, uint8_t *buf, uint64_t len) { uint64_t start, stop; diff --git a/src/fuzz.h b/src/fuzz.h index 493ad9c..482e268 100644 --- a/src/fuzz.h +++ b/src/fuzz.h @@ -16,5 +16,7 @@ * fuzz.h: fuzz functions */ +extern void _zz_setseed(int); +extern void _zz_setratio(float); extern void _zz_fuzz(int, uint8_t *, uint64_t); diff --git a/src/libzzuf.c b/src/libzzuf.c index d516fbb..9004e11 100644 --- a/src/libzzuf.c +++ b/src/libzzuf.c @@ -37,13 +37,14 @@ #include "libzzuf.h" #include "debug.h" #include "load.h" +#include "chars.h" +#include "fd.h" +#include "fuzz.h" /* Global variables */ int _zz_ready = 0; int _zz_disabled = 0; int _zz_hasdebug = 0; -float _zz_ratio = 0.004f; -int _zz_seed = 0; int _zz_signal = 0; int _zz_network = 0; @@ -51,15 +52,6 @@ int _zz_network = 0; int _zz_protect[256]; int _zz_refuse[256]; -/* Local variables */ -static regex_t * re_include = NULL; -static regex_t * re_exclude = NULL; - -/* Local prototypes */ -static void _zz_list_init(int *, char const *); -static void _zz_fd_init(void); -static void _zz_fd_fini(void); - /* Library initialisation shit */ void _zz_init(void) { @@ -71,23 +63,19 @@ void _zz_init(void) tmp = getenv("ZZUF_SEED"); if(tmp && *tmp) - _zz_seed = atol(tmp); + _zz_setseed(atol(tmp)); tmp = getenv("ZZUF_RATIO"); if(tmp && *tmp) - _zz_ratio = atof(tmp); - if(_zz_ratio < 0.0f) - _zz_ratio = 0.0f; - else if(_zz_ratio > 5.0f) - _zz_ratio = 5.0f; + _zz_setratio(atof(tmp)); tmp = getenv("ZZUF_PROTECT"); if(tmp && *tmp) - _zz_list_init(_zz_protect, tmp); + _zz_readchars(_zz_protect, tmp); tmp = getenv("ZZUF_REFUSE"); if(tmp && *tmp) - _zz_list_init(_zz_refuse, tmp); + _zz_readchars(_zz_refuse, tmp); tmp = getenv("ZZUF_INCLUDE"); if(tmp && *tmp) @@ -132,215 +120,3 @@ void _zz_fini(void) _zz_fd_fini(); } -/* Byte list stuff */ -static void _zz_list_init(int *table, char const *list) -{ - static char const hex[] = "0123456789abcdef0123456789ABCDEF"; - char const *tmp; - int a, b; - - memset(table, 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] >= '0' && tmp[0] <= '7' && tmp[1] >= '0' - && tmp[1] <= '7' && tmp[2] >= '0' && tmp[2] <= '7') - { - new = tmp[2] - '0'; - new |= (int)(tmp[1] - '0') << 3; - new |= (int)(tmp[0] - '0') << 6; - tmp += 2; - } - 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) - table[a++] = 1; - a = b = -1; - } - else - { - if(a != -1) - table[a] = 1; - a = b; - b = new; - } - } - - if(a != -1) - table[a] = 1; - if(b != -1) - table[b] = 1; -} - -/* File descriptor stuff */ -static struct files -{ - int managed; - uint64_t seed; - uint64_t pos; - /* Public stuff */ - struct fuzz fuzz; -} -*files; -static int *fds; -static int maxfd, nfiles; - -static void _zz_fd_init(void) -{ - files = NULL; - nfiles = 0; - - /* Start with one fd in the lookup table */ - fds = malloc(1 * sizeof(int)); - for(maxfd = 0; maxfd < 1; maxfd++) - fds[maxfd] = -1; -} - -static void _zz_fd_fini(void) -{ - int i; - - for(i = 0; i < maxfd; i++) - { - if(!files[fds[i]].managed) - continue; - - /* XXX: What are we supposed to do? If filedescriptors weren't - * closed properly, there's a leak, but it's not our problem. */ - } - - free(files); - free(fds); -} - -int _zz_mustwatch(char const *file) -{ - if(re_include && regexec(re_include, file, 0, NULL, 0) == REG_NOMATCH) - return 0; /* not included: ignore */ - - if(re_exclude && regexec(re_exclude, file, 0, NULL, 0) != REG_NOMATCH) - return 0; /* excluded: ignore */ - - return 1; /* default */ -} - -int _zz_iswatched(int fd) -{ - if(fd < 0 || fd >= maxfd || fds[fd] == -1) - return 0; - - return 1; -} - -void _zz_register(int fd) -{ - int i; - - if(fd < 0 || fd > 65535 || (fd < maxfd && fds[fd] != -1)) - return; - - while(fd >= maxfd) - { - fds = realloc(fds, 2 * maxfd * sizeof(int)); - for(i = maxfd; i < maxfd * 2; i++) - fds[i] = -1; - maxfd *= 2; - } - - /* Find an empty slot */ - for(i = 0; i < nfiles; i++) - if(files[i].managed == 0) - break; - - /* No slot found, allocate memory */ - if(i == nfiles) - { - nfiles++; - files = realloc(files, nfiles * sizeof(struct files)); - } - - files[i].managed = 1; - files[i].pos = 0; - files[i].fuzz.cur = -1; - files[i].fuzz.data = malloc(CHUNKBYTES); -#ifdef HAVE_FGETLN - files[i].fuzz.tmp = NULL; -#endif - - fds[fd] = i; -} - -void _zz_unregister(int fd) -{ - if(fd < 0 || fd >= maxfd || fds[fd] == -1) - return; - - files[fds[fd]].managed = 0; - free(files[fds[fd]].fuzz.data); -#ifdef HAVE_FGETLN - if(files[fds[fd]].fuzz.tmp) - free(files[fds[fd]].fuzz.tmp); -#endif - - fds[fd] = -1; -} - -long int _zz_getpos(int fd) -{ - if(fd < 0 || fd >= maxfd || fds[fd] == -1) - return 0; - - return files[fds[fd]].pos; -} - -void _zz_setpos(int fd, long int pos) -{ - if(fd < 0 || fd >= maxfd || fds[fd] == -1) - return; - - files[fds[fd]].pos = pos; -} - -void _zz_addpos(int fd, long int off) -{ - if(fd < 0 || fd >= maxfd || fds[fd] == -1) - return; - - files[fds[fd]].pos += off; -} - -struct fuzz *_zz_getfuzz(int fd) -{ - if(fd < 0 || fd >= maxfd || fds[fd] == -1) - return NULL; - - return &files[fds[fd]].fuzz; -} - diff --git a/src/libzzuf.h b/src/libzzuf.h index 7d76321..6051dda 100644 --- a/src/libzzuf.h +++ b/src/libzzuf.h @@ -38,8 +38,6 @@ struct fuzz extern int _zz_ready; extern int _zz_disabled; extern int _zz_hasdebug; -extern float _zz_ratio; -extern int _zz_seed; extern int _zz_signal; extern int _zz_network; @@ -51,13 +49,3 @@ extern int _zz_refuse[256]; extern void _zz_init(void) __attribute__((constructor)); extern void _zz_fini(void) __attribute__((destructor)); -/* File descriptor handling */ -extern int _zz_mustwatch(char const *); -extern int _zz_iswatched(int); -extern void _zz_register(int); -extern void _zz_unregister(int); -extern long int _zz_getpos(int); -extern void _zz_setpos(int, long int); -extern void _zz_addpos(int, long int); -extern struct fuzz *_zz_getfuzz(int); - diff --git a/src/load-fd.c b/src/load-fd.c index fdb65d8..47837de 100644 --- a/src/load-fd.c +++ b/src/load-fd.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,7 @@ #include "debug.h" #include "fuzz.h" #include "load.h" +#include "fd.h" /* Library functions that we divert */ static int (*open_orig) (const char *file, int oflag, ...); diff --git a/src/load-signal.c b/src/load-signal.c index 1eeb3b6..bed2037 100644 --- a/src/load-signal.c +++ b/src/load-signal.c @@ -28,6 +28,7 @@ #endif #include #include +#include #include #include diff --git a/src/load-stream.c b/src/load-stream.c index dc739ad..b440525 100644 --- a/src/load-stream.c +++ b/src/load-stream.c @@ -27,6 +27,7 @@ #endif #include #include +#include #include #include @@ -38,6 +39,7 @@ #include "debug.h" #include "fuzz.h" #include "load.h" +#include "fd.h" #if !defined __FreeBSD__ && !defined __OpenBSD__ # undef HAVE___SREFILL diff --git a/src/zzuf.c b/src/zzuf.c index 8c903e3..5faffbe 100644 --- a/src/zzuf.c +++ b/src/zzuf.c @@ -37,8 +37,11 @@ #include #include -#include "random.h" #include "libzzuf.h" +#include "random.h" +#include "chars.h" +#include "fd.h" +#include "fuzz.h" static void spawn_child(char **); static void clean_children(void); @@ -52,6 +55,10 @@ static void version(void); static void usage(void); #endif +/* Global tables */ +int _zz_protect[256]; +int _zz_refuse[256]; + static struct child_list { enum status @@ -90,9 +97,11 @@ static double maxtime = -1.0; int main(int argc, char *argv[]) { char **newargv; - char *parser, *include = NULL, *exclude = NULL; + char *parser, *include, *exclude, *protect, *refuse; int i, cmdline = 0; + include = exclude = protect = refuse = NULL; + #if defined(HAVE_GETOPT_H) for(;;) { @@ -172,20 +181,21 @@ int main(int argc, char *argv[]) setenv("ZZUF_NETWORK", "1", 1); break; case 'P': /* --protect */ - setenv("ZZUF_PROTECT", optarg, 1); + protect = optarg; break; case 'q': /* --quiet */ quiet = 1; break; case 'r': /* --ratio */ setenv("ZZUF_RATIO", optarg, 1); + _zz_setratio(atof(optarg)); break; case 'R': /* --refuse */ - setenv("ZZUF_REFUSE", optarg, 1); + refuse = optarg; break; case 's': /* --seed */ parser = strchr(optarg, ':'); - seed = atoi(optarg); + _zz_setseed(seed = atol(optarg)); endseed = parser ? atoi(parser + 1) : seed + 1; break; case 'S': /* --signal */ @@ -211,11 +221,42 @@ int main(int argc, char *argv[]) int optind = 1; #endif + /* If asked to read from the standard input */ if(optind >= argc) { - printf("%s: missing argument\n", argv[0]); - printf(MOREINFO, argv[0]); - return EXIT_FAILURE; + if(endseed != seed + 1) + { + printf("%s: seed ranges are incompatible with stdin fuzzing\n", + argv[0]); + printf(MOREINFO, argv[0]); + return EXIT_FAILURE; + } + + if(protect) + _zz_readchars(_zz_protect, protect); + if(refuse) + _zz_readchars(_zz_refuse, protect); + + _zz_fd_init(); + _zz_register(0); + + for(;;) + { + uint8_t buf[12]; + int ret = fread(buf, 1, 12, stdin); + if(ret <= 0) + break; + + _zz_fuzz(0, buf, ret); + _zz_addpos(0, ret); + + fwrite(buf, 1, ret, stdout); + } + + _zz_unregister(0); + _zz_fd_fini(); + + return EXIT_SUCCESS; } if(cmdline) @@ -237,6 +278,10 @@ int main(int argc, char *argv[]) setenv("ZZUF_INCLUDE", include, 1); if(exclude) setenv("ZZUF_EXCLUDE", exclude, 1); + if(protect) + setenv("ZZUF_PROTECT", protect, 1); + if(refuse) + setenv("ZZUF_REFUSE", refuse, 1); /* Allocate memory for children handling */ child_list = malloc(maxforks * sizeof(struct child_list));