From 728cfe90bf07f72d9e037574974b43f3d0e1f91f Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Fri, 22 Dec 2006 15:06:21 +0000 Subject: [PATCH] * Implement --max-bytes and --max-time. --- src/zzuf.c | 161 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 118 insertions(+), 43 deletions(-) diff --git a/src/zzuf.c b/src/zzuf.c index f7a421d..4ce1f23 100644 --- a/src/zzuf.c +++ b/src/zzuf.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include "random.h" @@ -43,10 +45,22 @@ static void version(void); static void usage(void); #endif +enum status +{ + STATUS_FREE, + STATUS_RUNNING, + STATUS_SIGTERM, + STATUS_SIGKILL, + STATUS_EOF, +}; + struct child_list { + enum status status; pid_t pid; - int outfd, errfd, seed; + int outfd, errfd; + int bytes, seed; + time_t date; } *child_list; int parallel = 1, child_count = 0; @@ -54,11 +68,23 @@ int parallel = 1, child_count = 0; int seed = 0; int endseed = 1; +#define ZZUF_FD_SET(fd, p_fdset, maxfd) \ + if(fd >= 0) \ + { \ + FD_SET(fd, p_fdset); \ + if(fd > maxfd) \ + maxfd = fd; \ + } + +#define ZZUF_FD_ISSET(fd, p_fdset) \ + ((fd >= 0) && (FD_ISSET(fd, p_fdset))) + int main(int argc, char *argv[]) { char **newargv; char *parser; - int i, j, quiet = 0; + int i, j, quiet = 0, maxbytes = -1; + double maxtime = -1.0; #if defined(HAVE_GETOPT_H) for(;;) @@ -69,21 +95,23 @@ int main(int argc, char *argv[]) static struct option long_options[] = { /* Long option, needs arg, flag, short option */ - { "include", 1, NULL, 'i' }, - { "exclude", 1, NULL, 'e' }, - { "seed", 1, NULL, 's' }, - { "ratio", 1, NULL, 'r' }, - { "fork", 1, NULL, 'F' }, - { "quiet", 0, NULL, 'q' }, - { "debug", 0, NULL, 'd' }, - { "help", 0, NULL, 'h' }, - { "version", 0, NULL, 'v' }, + { "include", 1, NULL, 'i' }, + { "exclude", 1, NULL, 'e' }, + { "seed", 1, NULL, 's' }, + { "ratio", 1, NULL, 'r' }, + { "fork", 1, NULL, 'F' }, + { "max-bytes", 1, NULL, 'B' }, + { "max-time", 1, NULL, 'T' }, + { "quiet", 0, NULL, 'q' }, + { "debug", 0, NULL, 'd' }, + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'v' }, }; - int c = getopt_long(argc, argv, "i:e:s:r:F:qdhv", + int c = getopt_long(argc, argv, "i:e:s:r:F:B:T:qdhv", long_options, &option_index); # else # define MOREINFO "Try `%s -h' for more information.\n" - int c = getopt(argc, argv, "i:e:s:r:F:qdhv"); + int c = getopt(argc, argv, "i:e:s:r:F:B:T:qdhv"); # endif if(c == -1) break; @@ -107,6 +135,12 @@ int main(int argc, char *argv[]) case 'F': /* --fork */ parallel = atoi(optarg) > 1 ? atoi(optarg) : 1; break; + case 'B': /* --max-bytes */ + maxbytes = atoi(optarg); + break; + case 'T': /* --max-time */ + maxtime = atof(optarg); + break; case 'q': /* --quiet */ quiet = 1; break; @@ -140,11 +174,7 @@ int main(int argc, char *argv[]) /* Allocate memory for children handling */ child_list = malloc(parallel * sizeof(struct child_list)); for(i = 0; i < parallel; i++) - { - child_list[i].pid = 0; - child_list[i].outfd = -1; - child_list[i].errfd = -1; - } + child_list[i].status = STATUS_FREE; child_count = 0; /* Preload libzzuf.so */ @@ -162,6 +192,7 @@ int main(int argc, char *argv[]) while(child_count || seed < endseed) { struct timeval tv; + time_t now = time(NULL); fd_set fdset; int ret, maxfd = 0; @@ -169,16 +200,53 @@ int main(int argc, char *argv[]) if(child_count < parallel && seed < endseed) spawn_child(newargv); - /* Kill dead children */ + /* Terminate children if necessary */ + for(i = 0; i < parallel; i++) + { + if(child_list[i].status == STATUS_RUNNING + && maxbytes >= 0 && child_list[i].bytes > maxbytes) + { + fprintf(stderr, "%i: exceeded byte count, sending SIGTERM\n", + child_list[i].seed); + kill(child_list[i].pid, SIGTERM); + child_list[i].date = now; + child_list[i].status = STATUS_SIGTERM; + } + + if(child_list[i].status == STATUS_RUNNING + && maxtime >= 0.0 + && difftime(now, child_list[i].date) > maxtime) + { + fprintf(stderr, "%i: time exceeded, sending SIGTERM\n", + child_list[i].seed); + kill(child_list[i].pid, SIGTERM); + child_list[i].date = now; + child_list[i].status = STATUS_SIGTERM; + } + } + + /* Kill children if necessary */ + for(i = 0; i < parallel; i++) + { + if(child_list[i].status == STATUS_SIGTERM + && difftime(now, child_list[i].date) > 2.0) + { + fprintf(stderr, "%i: not responding, sending SIGKILL\n", + child_list[i].seed); + kill(child_list[i].pid, SIGKILL); + child_list[i].status = STATUS_SIGKILL; + } + } + + /* Collect dead children */ for(i = 0; i < parallel; i++) { int status; pid_t pid; - if(!child_list[i].pid) - continue; - - if(child_list[i].outfd >= 0 || child_list[i].errfd >= 0) + if(child_list[i].status != STATUS_SIGKILL + && child_list[i].status != STATUS_SIGTERM + && child_list[i].status != STATUS_EOF) continue; pid = waitpid(child_list[i].pid, &status, WNOHANG); @@ -192,31 +260,25 @@ int main(int argc, char *argv[]) fprintf(stderr, "%i: signal %i\n", child_list[i].seed, WTERMSIG(status)); - child_list[i].pid = 0; - child_list[i].outfd = -1; - child_list[i].errfd = -1; + if(child_list[i].outfd >= 0) + close(child_list[i].outfd); + + if(child_list[i].errfd >= 0) + close(child_list[i].errfd); + + child_list[i].status = STATUS_FREE; child_count--; } + /* Read data from all sockets */ FD_ZERO(&fdset); for(i = 0; i < parallel; i++) { - if(!child_list[i].pid) + if(child_list[i].status != STATUS_RUNNING) continue; - if(child_list[i].outfd >= 0) - { - FD_SET(child_list[i].outfd, &fdset); - if(child_list[i].outfd > maxfd) - maxfd = child_list[i].outfd; - } - - if(child_list[i].errfd >= 0) - { - FD_SET(child_list[i].errfd, &fdset); - if(child_list[i].errfd > maxfd) - maxfd = child_list[i].errfd; - } + ZZUF_FD_SET(child_list[i].outfd, &fdset, maxfd); + ZZUF_FD_SET(child_list[i].errfd, &fdset, maxfd); } tv.tv_sec = 0; tv.tv_usec = 1000; @@ -232,17 +294,19 @@ int main(int argc, char *argv[]) char buf[BUFSIZ]; int fd; - if(!child_list[i].pid) + if(child_list[i].status != STATUS_RUNNING) continue; fd = j ? child_list[i].outfd : child_list[i].errfd; - if(fd < 0 || !FD_ISSET(fd, &fdset)) + if(!ZZUF_FD_ISSET(fd, &fdset)) continue; ret = read(fd, buf, BUFSIZ - 1); if(ret > 0) { + /* We got data */ + child_list[i].bytes += ret; if(!quiet) { buf[ret] = '\0'; @@ -252,11 +316,15 @@ int main(int argc, char *argv[]) } else if(ret == 0) { + /* End of file reached */ close(fd); if(j) child_list[i].outfd = -1; else child_list[i].errfd = -1; + + if(child_list[i].outfd == -1 && child_list[i].errfd == -1) + child_list[i].status = STATUS_EOF; } } } @@ -273,7 +341,7 @@ static void spawn_child(char **argv) /* Find an empty slot */ for(i = 0; i < parallel; i++) - if(child_list[i].pid == 0) + if(child_list[i].status == STATUS_FREE) break; /* Prepare communication pipe */ @@ -314,10 +382,13 @@ static void spawn_child(char **argv) /* We’re the parent, acknowledge spawn */ close(outfd[1]); close(errfd[1]); + child_list[i].date = time(NULL); child_list[i].pid = pid; child_list[i].outfd = outfd[0]; child_list[i].errfd = errfd[0]; + child_list[i].bytes = 0; child_list[i].seed = seed; + child_list[i].status = STATUS_RUNNING; child_count++; seed++; break; @@ -370,6 +441,8 @@ static void usage(void) printf(" -s, --seed random seed (default 0)\n"); printf(" --seed specify a seed range\n"); printf(" -F, --fork number of concurrent forks (default 1)\n"); + printf(" -B, --max-bytes kill children that output more than bytes\n"); + printf(" -T, --max-time kill children that run for more than seconds\n"); printf(" -q, --quiet do not print the fuzzed application's messages\n"); printf(" -d, --debug print debug messages\n"); printf(" -h, --help display this help and exit\n"); @@ -381,6 +454,8 @@ static void usage(void) printf(" -s random seed (default 0)\n"); printf(" specify a seed range\n"); printf(" -F number of concurrent forks (default 1)\n"); + printf(" -B kill children that output more than bytes\n"); + printf(" -T kill children that run for more than seconds\n"); printf(" -q do not print the fuzzed application's messages\n"); printf(" -d print debug messages\n"); printf(" -h display this help and exit\n");