diff --git a/src/fd.c b/src/fd.c index 855f9eb..5abd684 100644 --- a/src/fd.c +++ b/src/fd.c @@ -34,6 +34,7 @@ #include "debug.h" #include "libzzuf.h" #include "fd.h" +#include "fuzz.h" /* Regex stuff */ #if defined HAVE_REGEX_H @@ -41,6 +42,10 @@ static regex_t re_include, re_exclude; static int has_include = 0, has_exclude = 0; #endif +/* File descriptor cherry picking */ +static int *ranges = NULL; +static int ranges_static[512]; + /* File descriptor stuff. When program is launched, we use the static array of * 32 structures, which ought to be enough for most programs. If it happens * not to be the case, ie. if the process opens more than 32 file descriptors @@ -49,7 +54,7 @@ static int has_include = 0, has_exclude = 0; #define STATIC_FILES 32 static struct files { - int managed, locked; + int managed, locked, active; int64_t pos; /* Public stuff */ struct fuzz fuzz; @@ -89,6 +94,42 @@ void _zz_exclude(char const *regex) #endif } +/* This function is the same as _zz_bytes() */ +void _zz_pick(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_setseed(int32_t s) { seed = s; @@ -258,6 +299,26 @@ void _zz_register(int fd) #endif files[i].fuzz.uflag = 0; + /* Check whether we should ignore the fd */ + if(ranges) + { + static int idx = 0; + int *r; + + idx++; + + for(r = ranges; r[1]; r += 2) + if(idx >= r[0] && (r[0] == r[1] || idx < r[1])) + goto range_ok; + + files[i].active = 0; + } + else + { + range_ok: + files[i].active = 1; + } + if(autoinc) seed++; @@ -311,6 +372,14 @@ int _zz_islocked(int fd) return files[fds[fd]].locked; } +int _zz_isactive(int fd) +{ + if(fd < 0 || fd >= maxfd || fds[fd] == -1) + return 1; + + return files[fds[fd]].active; +} + int64_t _zz_getpos(int fd) { if(fd < 0 || fd >= maxfd || fds[fd] == -1) diff --git a/src/fd.h b/src/fd.h index 4432765..3e89a13 100644 --- a/src/fd.h +++ b/src/fd.h @@ -32,6 +32,7 @@ extern void _zz_unregister(int); extern void _zz_lock(int); extern void _zz_unlock(int); extern int _zz_islocked(int); +extern int _zz_isactive(int); extern int64_t _zz_getpos(int); extern void _zz_setpos(int, int64_t); extern void _zz_addpos(int, int64_t); diff --git a/src/fuzz.c b/src/fuzz.c index 3a48386..9be4a0e 100644 --- a/src/fuzz.c +++ b/src/fuzz.c @@ -64,6 +64,7 @@ extern void _zz_fuzzing(char const *mode) fuzzing = FUZZING_UNSET; } +/* This function is the same as _zz_pick() */ void _zz_bytes(char const *list) { char const *parser; diff --git a/src/fuzz.h b/src/fuzz.h index 0ac3b0e..e17b6b5 100644 --- a/src/fuzz.h +++ b/src/fuzz.h @@ -18,6 +18,7 @@ extern void _zz_fuzzing(char const *); extern void _zz_bytes(char const *); +extern void _zz_pick(char const *); extern void _zz_protect(char const *); extern void _zz_refuse(char const *); diff --git a/src/lib-fd.c b/src/lib-fd.c index fe981c6..1580725 100644 --- a/src/lib-fd.c +++ b/src/lib-fd.c @@ -207,7 +207,7 @@ RECV_T NEW(recv)(int s, void *buf, size_t len, int flags) LOADSYM(recv); ret = ORIG(recv)(s, buf, len, flags); - if(!_zz_ready || !_zz_iswatched(s) || _zz_islocked(s)) + if(!_zz_ready || !_zz_iswatched(s) || _zz_islocked(s) || !_zz_isactive(s)) return ret; if(ret > 0) @@ -240,7 +240,7 @@ RECV_T NEW(recvfrom)(int s, void *buf, size_t len, int flags, LOADSYM(recvfrom); ret = ORIG(recvfrom)(s, buf, len, flags, from, fromlen); - if(!_zz_ready || !_zz_iswatched(s) || _zz_islocked(s)) + if(!_zz_ready || !_zz_iswatched(s) || _zz_islocked(s) || !_zz_isactive(s)) return ret; if(ret > 0) @@ -273,7 +273,7 @@ RECV_T NEW(recvmsg)(int s, struct msghdr *hdr, int flags) LOADSYM(recvmsg); ret = ORIG(recvmsg)(s, hdr, flags); - if(!_zz_ready || !_zz_iswatched(s) || _zz_islocked(s)) + if(!_zz_ready || !_zz_iswatched(s) || _zz_islocked(s) || !_zz_isactive(s)) return ret; fuzz_iovec(s, hdr->msg_iov, ret); @@ -293,7 +293,8 @@ int NEW(read)(int fd, void *buf, unsigned int count) LOADSYM(read); ret = ORIG(read)(fd, buf, count); - if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd)) + if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd) + || !_zz_isactive(fd)) return ret; if(ret > 0) @@ -324,7 +325,8 @@ ssize_t NEW(readv)(int fd, const struct iovec *iov, int count) LOADSYM(readv); ret = ORIG(readv)(fd, iov, count); - if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd)) + if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd) + || !_zz_isactive(fd)) return ret; fuzz_iovec(fd, iov, ret); @@ -342,7 +344,8 @@ ssize_t NEW(pread)(int fd, void *buf, size_t count, off_t offset) LOADSYM(pread); ret = ORIG(pread)(fd, buf, count, offset); - if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd)) + if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd) + || !_zz_isactive(fd)) return ret; if(ret > 0) @@ -375,7 +378,8 @@ ssize_t NEW(pread)(int fd, void *buf, size_t count, off_t offset) { \ LOADSYM(fn); \ ret = ORIG(fn)(fd, offset, whence); \ - if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd)) \ + if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd) \ + || !_zz_isactive(fd)) \ return ret; \ debug("%s(%i, %lli, %i) = %lli", __func__, fd, \ (long long int)offset, whence, (long long int)ret); \ @@ -406,7 +410,7 @@ int NEW(aio_read)(struct aiocb *aiocbp) int fd = aiocbp->aio_fildes; LOADSYM(aio_read); - if(!_zz_ready || !_zz_iswatched(fd)) + if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) return ORIG(aio_read)(aiocbp); _zz_lock(fd); @@ -425,7 +429,7 @@ ssize_t NEW(aio_return)(struct aiocb *aiocbp) int fd = aiocbp->aio_fildes; LOADSYM(aio_return); - if(!_zz_ready || !_zz_iswatched(fd)) + if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) return ORIG(aio_return)(aiocbp); ret = ORIG(aio_return)(aiocbp); diff --git a/src/lib-mem.c b/src/lib-mem.c index eb509c4..7e716ca 100644 --- a/src/lib-mem.c +++ b/src/lib-mem.c @@ -223,7 +223,8 @@ int nbmaps = 0; do { \ char *b = MAP_FAILED; \ LOADSYM(fn); \ - if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd)) \ + if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd) \ + || !_zz_isactive(fd)) \ return ORIG(fn)(start, length, prot, flags, fd, offset); \ ret = ORIG(fn)(NULL, length, prot, flags, fd, offset); \ if(ret != MAP_FAILED && length) \ @@ -317,7 +318,8 @@ kern_return_t NEW(map_fd)(int fd, vm_offset_t offset, vm_offset_t *addr, LOADSYM(map_fd); ret = ORIG(map_fd)(fd, offset, addr, find_space, numbytes); - if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd)) + if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd) + || !_zz_isactive(fd)) return ret; if(ret == 0 && numbytes) diff --git a/src/lib-stream.c b/src/lib-stream.c index 7c59731..6a79528 100644 --- a/src/lib-stream.c +++ b/src/lib-stream.c @@ -175,7 +175,7 @@ FILE *NEW(freopen)(const char *path, const char *mode, FILE *stream) int fd; \ LOADSYM(fn); \ fd = fileno(stream); \ - if(!_zz_ready || !_zz_iswatched(fd)) \ + if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \ return ORIG(fn)(stream, offset, whence); \ _zz_lock(fd); \ ret = ORIG(fn)(stream, offset, whence); \ @@ -203,7 +203,7 @@ void NEW(rewind)(FILE *stream) LOADSYM(rewind); fd = fileno(stream); - if(!_zz_ready || !_zz_iswatched(fd)) + if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) { ORIG(rewind)(stream); return; @@ -233,7 +233,7 @@ size_t NEW(fread)(void *ptr, size_t size, size_t nmemb, FILE *stream) LOADSYM(fread); fd = fileno(stream); - if(!_zz_ready || !_zz_iswatched(fd)) + if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) return ORIG(fread)(ptr, size, nmemb, stream); pos = ftell(stream); @@ -294,7 +294,7 @@ size_t NEW(fread)(void *ptr, size_t size, size_t nmemb, FILE *stream) int fd; \ LOADSYM(fn); \ fd = fileno(stream); \ - if(!_zz_ready || !_zz_iswatched(fd)) \ + if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \ return ORIG(fn)(stream); \ _zz_lock(fd); \ ret = ORIG(fn)(stream); \ @@ -332,7 +332,7 @@ char *NEW(fgets)(char *s, int size, FILE *stream) LOADSYM(fgets); LOADSYM(fgetc); fd = fileno(stream); - if(!_zz_ready || !_zz_iswatched(fd)) + if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) return ORIG(fgets)(s, size, stream); #if defined HAVE___SREFILL /* Don't fuzz or seek if we have __srefill() */ @@ -385,7 +385,7 @@ int NEW(ungetc)(int c, FILE *stream) LOADSYM(ungetc); fd = fileno(stream); - if(!_zz_ready || !_zz_iswatched(fd)) + if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) return ORIG(ungetc)(c, stream); _zz_lock(fd); @@ -439,7 +439,7 @@ int NEW(fclose)(FILE *fp) LOADSYM(getdelim); \ LOADSYM(fgetc); \ fd = fileno(stream); \ - if(!_zz_ready || !_zz_iswatched(fd)) \ + if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) \ return ORIG(getdelim)(lineptr, n, delim, stream); \ line = *lineptr; \ size = line ? *n : 0; \ @@ -521,7 +521,7 @@ char *NEW(fgetln)(FILE *stream, size_t *len) LOADSYM(fgetln); LOADSYM(fgetc); fd = fileno(stream); - if(!_zz_ready || !_zz_iswatched(fd)) + if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) return ORIG(fgetln)(stream, len); #if defined HAVE___SREFILL /* Don't fuzz or seek if we have __srefill() */ @@ -570,7 +570,7 @@ int NEW(__srefill)(FILE *fp) LOADSYM(__srefill); fd = fileno(fp); - if(!_zz_ready || !_zz_iswatched(fd)) + if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd)) return ORIG(__srefill)(fp); _zz_lock(fd); diff --git a/src/libzzuf.c b/src/libzzuf.c index ebf540d..f4e2759 100644 --- a/src/libzzuf.c +++ b/src/libzzuf.c @@ -90,6 +90,10 @@ void _zz_init(void) if(tmp && *tmp) _zz_bytes(tmp); + tmp = getenv("ZZUF_PICK"); + if(tmp && *tmp) + _zz_pick(tmp); + tmp = getenv("ZZUF_PROTECT"); if(tmp && *tmp) _zz_protect(tmp); diff --git a/src/opts.c b/src/opts.c index 8011074..18309b9 100644 --- a/src/opts.c +++ b/src/opts.c @@ -33,7 +33,8 @@ void _zz_opts_init(struct opts *opts) { - opts->fuzzing = opts->bytes = opts->protect = opts->refuse = NULL; + opts->fuzzing = opts->bytes = opts->pick = NULL; + opts->protect = opts->refuse = NULL; opts->seed = DEFAULT_SEED; opts->endseed = DEFAULT_SEED + 1; opts->minratio = opts->maxratio = DEFAULT_RATIO; diff --git a/src/opts.h b/src/opts.h index 9130cba..ae0e63b 100644 --- a/src/opts.h +++ b/src/opts.h @@ -20,7 +20,7 @@ struct opts { char **oldargv; char **newargv; - char *fuzzing, *bytes, *protect, *refuse; + char *fuzzing, *bytes, *pick, *protect, *refuse; uint32_t seed; uint32_t endseed; double minratio; diff --git a/src/zzuf.c b/src/zzuf.c index d5bfd66..8025ccc 100644 --- a/src/zzuf.c +++ b/src/zzuf.c @@ -157,7 +157,7 @@ int main(int argc, char *argv[]) # define OPTSTR_RLIMIT "" #endif #define OPTSTR OPTSTR_REGEX OPTSTR_RLIMIT \ - "Ab:B:C:dD:f:F:imnP:qr:R:s:ST:vxhV" + "Ab:B:C:dD:f:F:imnp:P:qr:R:s:ST:vxhV" #define MOREINFO "Try `%s --help' for more information.\n" int option_index = 0; static struct myoption long_options[] = @@ -184,6 +184,7 @@ int main(int argc, char *argv[]) { "md5", 0, NULL, 'm' }, { "max-memory", 1, NULL, 'M' }, { "network", 0, NULL, 'n' }, + { "pick", 1, NULL, 'p' }, { "protect", 1, NULL, 'P' }, { "quiet", 0, NULL, 'q' }, { "ratio", 1, NULL, 'r' }, @@ -274,6 +275,9 @@ int main(int argc, char *argv[]) case 'n': /* --network */ setenv("ZZUF_NETWORK", "1", 1); break; + case 'p': /* --pick */ + opts->pick = myoptarg; + break; case 'P': /* --protect */ opts->protect = myoptarg; break; @@ -375,6 +379,8 @@ int main(int argc, char *argv[]) setenv("ZZUF_FUZZING", opts->fuzzing, 1); if(opts->bytes) setenv("ZZUF_BYTES", opts->bytes, 1); + if(opts->pick) + setenv("ZZUF_PICK", opts->pick, 1); if(opts->protect) setenv("ZZUF_PROTECT", opts->protect, 1); if(opts->refuse) @@ -427,6 +433,8 @@ static void loop_stdin(struct opts *opts) _zz_fuzzing(opts->fuzzing); if(opts->bytes) _zz_bytes(opts->bytes); + if(opts->pick) + _zz_pick(opts->pick); if(opts->protect) _zz_protect(opts->protect); if(opts->refuse) @@ -1085,9 +1093,10 @@ static void usage(void) printf(" [-T seconds] [-b ranges] [-P protect] [-R refuse]\n"); #endif #if defined HAVE_REGEX_H - printf(" [-I include] [-E exclude] [PROGRAM [--] [ARGS]...]\n"); -#else + printf(" [-p descriptors] [-I include] [-E exclude]\n"); printf(" [PROGRAM [--] [ARGS]...]\n"); +#else + printf(" [-I include] [-E exclude] [PROGRAM [--] [ARGS]...]\n"); #endif printf(" zzuf -h | --help\n"); printf(" zzuf -V | --version\n"); @@ -1117,6 +1126,7 @@ static void usage(void) printf(" -M, --max-memory maximum child virtual memory size in MB\n"); #endif printf(" -n, --network fuzz network input\n"); + printf(" -p, --pick only fuzz Nth descriptor with N in \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);