From 8f431fbd831b3832d8ee255befeeef2ef2aa61d2 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Thu, 6 Aug 2009 21:17:00 +0000 Subject: [PATCH] Allow remote network host filtering, courtesy of Corentin Delorme. --- AUTHORS | 4 +- src/Makefile.am | 3 +- src/fd.c | 22 +----- src/fd.h | 3 +- src/fuzz.h | 3 +- src/lib-fd.c | 16 ++-- src/libzzuf.c | 13 +++- src/network.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++ src/network.h | 28 +++++++ src/opts.c | 3 +- src/opts.h | 4 +- src/zzuf.c | 44 +++++++++-- 12 files changed, 295 insertions(+), 43 deletions(-) create mode 100644 src/network.c create mode 100644 src/network.h diff --git a/AUTHORS b/AUTHORS index 4844f85..4ad8350 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,10 +1,12 @@ $Id$ main zzuf author: - Sam Hocevar + Sam Hocevar other contributors: Rémi Denis-Courmont (readv, recvmsg) Clément Stenac (pread) Dominik Kuhlen (recvfrom) Sami Liedes (LD_PRELOAD conservation) + Corentin Delorme (remote host filtering) + diff --git a/src/Makefile.am b/src/Makefile.am index e07ca23..8af2837 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,7 +13,8 @@ zzuf_LDFLAGS = $(MATH_LIBS) $(WINSOCK2_LIBS) zzuf_DEPENDENCIES = libzzuf.la pkglib_LTLIBRARIES = libzzuf.la -libzzuf_la_SOURCES = libzzuf.c libzzuf.h $(COMMON) debug.c debug.h sys.c sys.h \ +libzzuf_la_SOURCES = libzzuf.c libzzuf.h $(COMMON) debug.c debug.h \ + sys.c sys.h network.c network.h \ lib-fd.c lib-mem.c lib-signal.c lib-stream.c lib-load.h libzzuf_la_CFLAGS = -DLIBZZUF libzzuf_la_LDFLAGS = -avoid-version -no-undefined $(DLL_LDFLAGS) diff --git a/src/fd.c b/src/fd.c index 36dca0b..59fbf0b 100644 --- a/src/fd.c +++ b/src/fd.c @@ -1,6 +1,6 @@ /* * zzuf - general purpose fuzzer - * Copyright (c) 2006-2007 Sam Hocevar + * Copyright (c) 2006-2009 Sam Hocevar * All Rights Reserved * * $Id$ @@ -35,6 +35,7 @@ #include "libzzuf.h" #include "fd.h" #include "fuzz.h" +#include "network.h" #include "ranges.h" /* Regex stuff */ @@ -43,10 +44,6 @@ static regex_t re_include, re_exclude; static int has_include = 0, has_exclude = 0; #endif -/* Network port cherry picking */ -static int *ports = NULL; -static int static_ports[512]; - /* File descriptor cherry picking */ static int *list = NULL; static int static_list[512]; @@ -99,11 +96,6 @@ void _zz_exclude(char const *regex) #endif } -void _zz_ports(char const *portlist) -{ - ports = _zz_allocrange(portlist, static_ports); -} - void _zz_list(char const *fdlist) { list = _zz_allocrange(fdlist, static_list); @@ -199,8 +191,6 @@ void _zz_fd_fini(void) free(fds); if(list != static_list) free(list); - if(ports != static_ports) - free(ports); } int _zz_mustwatch(char const *file) @@ -226,14 +216,6 @@ int _zz_iswatched(int fd) return 1; } -int _zz_portwatched(int port) -{ - if(!ports) - return 1; - - return _zz_isinrange(port, ports); -} - void _zz_register(int fd) { int i; diff --git a/src/fd.h b/src/fd.h index cc64d45..26d01b2 100644 --- a/src/fd.h +++ b/src/fd.h @@ -1,6 +1,6 @@ /* * zzuf - general purpose fuzzer - * Copyright (c) 2006 Sam Hocevar + * Copyright (c) 2006-2009 Sam Hocevar * All Rights Reserved * * $Id$ @@ -26,7 +26,6 @@ extern void _zz_fd_init(void); extern void _zz_fd_fini(void); extern int _zz_mustwatch(char const *); -extern int _zz_portwatched(int); extern int _zz_iswatched(int); extern void _zz_register(int); extern void _zz_unregister(int); diff --git a/src/fuzz.h b/src/fuzz.h index f15c740..36bcc14 100644 --- a/src/fuzz.h +++ b/src/fuzz.h @@ -1,6 +1,6 @@ /* * zzuf - general purpose fuzzer - * Copyright (c) 2006 Sam Hocevar + * Copyright (c) 2006-2009 Sam Hocevar * All Rights Reserved * * $Id$ @@ -19,7 +19,6 @@ extern void _zz_fuzzing(char const *); extern void _zz_bytes(char const *); extern void _zz_list(char const *); -extern void _zz_ports(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 69b297f..9cb5fed 100644 --- a/src/lib-fd.c +++ b/src/lib-fd.c @@ -1,9 +1,10 @@ /* * zzuf - general purpose fuzzer - * Copyright (c) 2006, 2007 Sam Hocevar + * Copyright (c) 2006-2009 Sam Hocevar * 2007 Rémi Denis-Courmont * 2007 Clément Stenac * 2007 Dominik Kuhlen + * 2009 Corentin Delorme * All Rights Reserved * * $Id$ @@ -351,7 +352,8 @@ 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) || !_zz_isactive(s)) + if(!_zz_ready || !_zz_iswatched(s) || !_zz_hostwatched(s) + || _zz_islocked(s) || !_zz_isactive(s)) return ret; if(ret > 0) @@ -384,7 +386,8 @@ 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) || !_zz_isactive(s)) + if(!_zz_ready || !_zz_iswatched(s) || !_zz_hostwatched(s) + || _zz_islocked(s) || !_zz_isactive(s)) return ret; if(ret > 0) @@ -424,7 +427,8 @@ 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) || !_zz_isactive(s)) + if(!_zz_ready || !_zz_iswatched(s) || !_zz_hostwatched(s) + || _zz_islocked(s) || !_zz_isactive(s)) return ret; fuzz_iovec(s, hdr->msg_iov, ret); @@ -444,8 +448,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) - || !_zz_isactive(fd)) + if(!_zz_ready || !_zz_iswatched(fd) || !_zz_hostwatched(fd) + || _zz_islocked(fd) || !_zz_isactive(fd)) return ret; if(ret > 0) diff --git a/src/libzzuf.c b/src/libzzuf.c index fe27601..01cde44 100644 --- a/src/libzzuf.c +++ b/src/libzzuf.c @@ -1,6 +1,6 @@ /* * zzuf - general purpose fuzzer - * Copyright (c) 2006 Sam Hocevar + * Copyright (c) 2006-2009 Sam Hocevar * All Rights Reserved * * $Id$ @@ -44,6 +44,7 @@ #include "libzzuf.h" #include "debug.h" #include "fd.h" +#include "network.h" #include "sys.h" #include "fuzz.h" @@ -140,6 +141,14 @@ void _zz_init(void) if(tmp && *tmp) _zz_ports(tmp); + tmp = getenv("ZZUF_ALLOW"); + if(tmp && *tmp) + _zz_allow(tmp); + + tmp = getenv("ZZUF_DENY"); + if(tmp && *tmp) + _zz_deny(tmp); + tmp = getenv("ZZUF_PROTECT"); if(tmp && *tmp) _zz_protect(tmp); @@ -169,6 +178,7 @@ void _zz_init(void) _zz_network = 1; _zz_fd_init(); + _zz_network_init(); _zz_sys_init(); tmp = getenv("ZZUF_STDIN"); @@ -188,6 +198,7 @@ void _zz_init(void) void _zz_fini(void) { _zz_fd_fini(); + _zz_network_fini(); } #if defined HAVE_WINDOWS_H diff --git a/src/network.c b/src/network.c new file mode 100644 index 0000000..5c25758 --- /dev/null +++ b/src/network.c @@ -0,0 +1,195 @@ +/* + * zzuf - general purpose fuzzer + * Copyright (c) 2006-2009 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. + */ + +/* + * network.c: network connection helper functions + */ + +#include "config.h" + +#if defined HAVE_STDINT_H +# include +#elif defined HAVE_INTTYPES_H +# include +#endif +#include +#include +#include +#include +#include +#include + +#include "libzzuf.h" +#include "debug.h" +#include "ranges.h" +#include "network.h" + +static unsigned int get_socket_ip(int); +static int host_in_list(unsigned int, unsigned int const *); +static unsigned int *create_host_list(char const *, unsigned int *); + +/* Network IP cherry picking */ +static unsigned int *allow = NULL; +static unsigned int static_allow[512]; +static unsigned int *deny = NULL; +static unsigned int static_deny[512]; + +/* Network port cherry picking */ +static int *ports = NULL; +static int static_ports[512]; + +void _zz_network_init(void) +{ + ; +} + +void _zz_network_fini(void) +{ + if(ports != static_ports) + free(ports); + if(allow != static_allow) + free(allow); + if(deny != static_deny) + free(deny); +} + +void _zz_allow(char const *allowlist) +{ + allow = create_host_list(allowlist, static_allow); +} + +void _zz_deny(char const *denylist) +{ + deny = create_host_list(denylist, static_deny); +} + +void _zz_ports(char const *portlist) +{ + ports = _zz_allocrange(portlist, static_ports); +} + +int _zz_portwatched(int port) +{ + if(!ports) + return 1; + + return _zz_isinrange(port, ports); +} + +int _zz_hostwatched(int sock) +{ + int watch = 1; + unsigned int ip; + + if(!allow && !deny) + return 1; + + ip = get_socket_ip(sock); + + if(deny && host_in_list(ip, deny)) + watch = 0; + if(allow) + watch = host_in_list(ip, allow); + + return watch; +} + +/* XXX: the following functions are local */ + +static unsigned int *create_host_list(char const *list, + unsigned int *static_list) +{ + int ret; + char *copy; + char *parser; + struct in_addr addr; + unsigned int i, chunks, len, *iplist; + + len = strlen(list); + copy = malloc(len + 1); + if (!copy) { + // TODO better error handling + perror("malloc"); + exit(EXIT_FAILURE); + } + strncpy(copy, list, len); + copy[len] = 0; + + /* Count commas */ + for(parser = copy, chunks = 1; *parser; parser++) + if(*parser == ',') + chunks++; + + if(chunks >= 512) + iplist = malloc((chunks + 1) * sizeof(unsigned int)); + else + iplist = static_list; + + for(parser = copy, i = 0; i < chunks; i++) + { + char *comma = strchr(parser, ','); + if (comma) + *comma = 0; + + ret = inet_aton(parser, &addr); + if (ret) + iplist[i] = addr.s_addr; + else { + i--; + chunks--; + debug("create_host_list: Invalid IP address '%s'. Skipping it.", parser); + } + parser = comma + 1; + } + + iplist[i] = 0; + free(copy); + + return iplist; +} + +static int host_in_list(unsigned int value, unsigned int const *list) +{ + unsigned int i; + + if (!value || !list) + return 0; + + for (i = 0; list[i]; i++) + if (value == list[i]) + return 1; + + return 0; +} + +static unsigned int get_socket_ip(int sock) +{ + int ret; + struct sockaddr_in sin; + socklen_t len = sizeof(sin); + + // Probably not a socket descriptor + if (sock < 3) + return 0; + + memset(&sin, 0, sizeof(sin)); + ret = getsockname(sock, &sin, &len); + if (ret) { + // TODO error handling + return 0; + } + + return sin.sin_addr.s_addr; +} + diff --git a/src/network.h b/src/network.h new file mode 100644 index 0000000..c5a4e61 --- /dev/null +++ b/src/network.h @@ -0,0 +1,28 @@ +/* + * zzuf - general purpose fuzzer + * Copyright (c) 2006-2009 Sam Hocevar + * 2009 Corentin Delorme + * 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. + */ + +/* + * network.h: network connection helper functions + */ + +extern void _zz_ports(char const *); +extern void _zz_allow(char const *); +extern void _zz_deny(char const *); +extern void _zz_network_init(void); +extern void _zz_network_fini(void); + +extern int _zz_portwatched(int); +extern int _zz_hostwatched(int); + diff --git a/src/opts.c b/src/opts.c index eda11a1..0899ebc 100644 --- a/src/opts.c +++ b/src/opts.c @@ -1,6 +1,6 @@ /* * zzuf - general purpose fuzzer - * Copyright (c) 2002, 2007 Sam Hocevar + * Copyright (c) 2002, 2007-2009 Sam Hocevar * All Rights Reserved * * $Id$ @@ -34,6 +34,7 @@ void _zz_opts_init(struct opts *opts) { opts->fuzzing = opts->bytes = opts->list = opts->ports = NULL; + opts->allow = opts->deny = NULL; opts->protect = opts->refuse = NULL; opts->seed = DEFAULT_SEED; opts->endseed = DEFAULT_SEED + 1; diff --git a/src/opts.h b/src/opts.h index 7ab05ae..fa157ef 100644 --- a/src/opts.h +++ b/src/opts.h @@ -1,6 +1,6 @@ /* * zzuf - general purpose fuzzer - * Copyright (c) 2002, 2007 Sam Hocevar + * Copyright (c) 2002, 2007-2009 Sam Hocevar * All Rights Reserved * * $Id$ @@ -20,7 +20,7 @@ struct opts { char **oldargv; char **newargv; - char *fuzzing, *bytes, *list, *ports, *protect, *refuse; + char *fuzzing, *bytes, *list, *ports, *protect, *refuse, *allow, *deny; uint32_t seed; uint32_t endseed; double minratio; diff --git a/src/zzuf.c b/src/zzuf.c index c40afef..c3f5fc8 100644 --- a/src/zzuf.c +++ b/src/zzuf.c @@ -1,6 +1,6 @@ /* * zzuf - general purpose fuzzer - * Copyright (c) 2002, 2007 Sam Hocevar + * Copyright (c) 2002, 2007-2009 Sam Hocevar * All Rights Reserved * * $Id$ @@ -175,12 +175,13 @@ int main(int argc, char *argv[]) # define OPTSTR_RLIMIT_CPU "" #endif #define OPTSTR "+" OPTSTR_REGEX OPTSTR_RLIMIT_MEM OPTSTR_RLIMIT_CPU \ - "Ab:B:C:dD:f:F:ij:l:mnp:P:qr:R:s:St:vxhV" + "a:Ab:B:C:dD:e:f:F:ij:l:mnp:P:qr:R:s:St:vxhV" #define MOREINFO "Try `%s --help' for more information.\n" int option_index = 0; static struct myoption long_options[] = { /* Long option, needs arg, flag, short option */ + { "allow", 1, NULL, 'a' }, { "autoinc", 0, NULL, 'A' }, { "bytes", 1, NULL, 'b' }, { "max-bytes", 1, NULL, 'B' }, @@ -190,6 +191,7 @@ int main(int argc, char *argv[]) { "max-crashes", 1, NULL, 'C' }, { "debug", 0, NULL, 'd' }, { "delay", 1, NULL, 'D' }, + { "deny", 1, NULL, 'e' }, #if defined HAVE_REGEX_H { "exclude", 1, NULL, 'E' }, #endif @@ -225,6 +227,9 @@ int main(int argc, char *argv[]) switch(c) { + case 'a': /* --allow */ + opts->allow = myoptarg; + break; case 'A': /* --autoinc */ setenv("ZZUF_AUTOINC", "1", 1); break; @@ -256,6 +261,9 @@ int main(int argc, char *argv[]) myoptarg++; opts->delay = (int64_t)(atof(myoptarg) * 1000000.0); break; + case 'e': /* --deny */ + opts->deny = myoptarg; + break; #if defined HAVE_REGEX_H case 'E': /* --exclude */ exclude = merge_regex(exclude, myoptarg); @@ -386,6 +394,24 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } + if (opts->allow && !network) + { + fprintf(stderr, "%s: allow option (-a) requires network fuzzing (-n)\n", + argv[0]); + printf(MOREINFO, argv[0]); + _zz_opts_fini(opts); + return EXIT_FAILURE; + } + + if (opts->deny && !network) + { + fprintf(stderr, "%s: deny option (-e) requires network fuzzing (-n)\n", + argv[0]); + printf(MOREINFO, argv[0]); + _zz_opts_fini(opts); + return EXIT_FAILURE; + } + _zz_setratio(opts->minratio, opts->maxratio); _zz_setseed(opts->seed); @@ -444,6 +470,10 @@ int main(int argc, char *argv[]) setenv("ZZUF_LIST", opts->list, 1); if(opts->ports) setenv("ZZUF_PORTS", opts->ports, 1); + if(opts->allow) + setenv("ZZUF_ALLOW", opts->allow, 1); + if(opts->deny) + setenv("ZZUF_DENY", opts->deny, 1); if(opts->protect) setenv("ZZUF_PROTECT", opts->protect, 1); if(opts->refuse) @@ -499,8 +529,6 @@ static void loop_stdin(struct opts *opts) _zz_bytes(opts->bytes); if(opts->list) _zz_list(opts->list); - if(opts->ports) - _zz_ports(opts->ports); if(opts->protect) _zz_protect(opts->protect); if(opts->refuse) @@ -1182,13 +1210,13 @@ static void *get_entry(char const *name) static void version(void) { printf("zzuf %s\n", PACKAGE_VERSION); - printf("Copyright (C) 2002, 2007-2008 Sam Hocevar \n"); + printf("Copyright (C) 2002, 2007-2009 Sam Hocevar \n"); printf("This program is free software. It comes without any warranty, to the extent\n"); printf("permitted by applicable law. You can redistribute it and/or modify it under\n"); printf("the terms of the Do What The Fuck You Want To Public License, Version 2, as\n"); printf("published by Sam Hocevar. See for more details.\n"); printf("\n"); - printf("Written by Sam Hocevar. Report bugs to .\n"); + printf("Written by Sam Hocevar. Report bugs to .\n"); } static void usage(void) @@ -1218,6 +1246,7 @@ static void usage(void) printf("Run PROGRAM with optional arguments ARGS and fuzz its input.\n"); printf("\n"); printf("Mandatory arguments to long options are mandatory for short options too.\n"); + printf(" -a, --allow only fuzz network input for IPs in \n"); printf(" -A, --autoinc increment seed each time a new file is opened\n"); printf(" -b, --bytes only fuzz bytes at offsets within \n"); printf(" -B, --max-bytes kill children that output more than bytes\n"); @@ -1227,6 +1256,7 @@ static void usage(void) 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, --deny do not fuzz network input for IPs in \n"); #if defined HAVE_REGEX_H printf(" -E, --exclude do not fuzz files matching \n"); #endif @@ -1258,6 +1288,6 @@ static void usage(void) printf(" -h, --help display this help and exit\n"); printf(" -V, --version output version information and exit\n"); printf("\n"); - printf("Written by Sam Hocevar. Report bugs to .\n"); + printf("Written by Sam Hocevar. Report bugs to .\n"); }