* Implemented memory limits. Probably breaks on other arches because of all
the new functions.
This commit is contained in:
+23
-9
@@ -2,11 +2,11 @@
|
||||
.SH NAME
|
||||
zzuf \- multiple purpose fuzzer
|
||||
.SH SYNOPSIS
|
||||
\fBzzuf\fR [\fB\-cdiMnqS\fR] [\fB\-r\fR \fIratio\fR] [\fB\-s\fR \fIseed\fR | \fB\-s\fR \fIstart:stop\fR]
|
||||
\fBzzuf\fR [\fB\-cdiMnqS\fR] [\fB\-r\fR \fIratio\fR] [\fB\-s\fR \fIseed\fR|\fB\-s\fR \fIstart:stop\fR]
|
||||
.br
|
||||
[\fB\-F\fR \fIforks\fR] [\fB\-C\fR \fIcrashes\fR] [\fB\-B\fR \fIbytes\fR] [\fB\-T\fR \fIseconds\fR]
|
||||
.br
|
||||
[\fB\-P\fR \fIprotect\fR] [\fB\-R\fR \fIrefuse\fR]
|
||||
[\fB\-M\fR \fImegabytes\fR] [\fB\-P\fR \fIprotect\fR] [\fB\-R\fR \fIrefuse\fR]
|
||||
.br
|
||||
[\fB\-I\fR \fIinclude\fR] [\fB\-E\fR \fIexclude\fR] [\fIPROGRAM\fR [\fIARGS\fR]...]
|
||||
.br
|
||||
@@ -99,6 +99,15 @@ of the regular expressions will be fuzzed. See also the \fB\-c\fR flag.
|
||||
Instead of displaying the program's standard output, just print the MD5 digest
|
||||
of that output. The standard error channel is left untouched.
|
||||
.TP
|
||||
\fB\-M\fR, \fB\-\-max-memory\fR=\fImegabytes\fR
|
||||
Specify the maximum amount of memory, in megabytes, that children are allowed
|
||||
to allocate. This is useful to detect infinite loops that eat up a lot of
|
||||
memory. The value should set reasonably high so as not to interfer with normal
|
||||
program operation.
|
||||
|
||||
\fBZzuf\fR uses the \fBsetrlimit\fR() call to set memory usage limitations and
|
||||
relies on the operating system's ability to enforce such limitations.
|
||||
.TP
|
||||
\fB\-n\fR, \fB\-\-network\fR
|
||||
Fuzz the application's network input. By default \fBzzuf\fR only fuzzes files.
|
||||
.TP
|
||||
@@ -227,7 +236,7 @@ can be read by \fBVLC\fR to reproduce the same behaviour without using
|
||||
\fBzzuf\fR:
|
||||
.PP
|
||||
\fB zzuf \-c \-s 87423 \-r 0.01 vlc movie.avi\fR
|
||||
\fB zzuf \-c \-s 87423 \-r 0.01 cp movie.avi fuzzy\-movie.avi\fR
|
||||
\fB zzuf \-c \-s 87423 \-r 0.01 <movie.avi >fuzzy\-movie.avi\fR
|
||||
\fB vlc fuzzy\-movie.avi\fR
|
||||
.PP
|
||||
Fuzz 2% of \fBMPlayer\fR's input bits (\fB\-r\ 0.02\fR) with seeds 0 to 9999
|
||||
@@ -240,8 +249,8 @@ and disabling its \fBSIGSEGV\fR signal handler (\fB\-S\fR):
|
||||
\fB mplayer \-\- \-benchmark \-vo null \-fps 1000 movie.avi\fR
|
||||
.SH RESTRICTIONS
|
||||
.PP
|
||||
Due to \fBzzuf\fR using shared object preloading (\fBLD_PRELOAD\fR on most
|
||||
Unix systems, \fBDYLD_INSERT_LIBRARIES\fR on Mac OS X) to run its child
|
||||
Due to \fBzzuf\fR using shared object preloading (\fBLD_PRELOAD\fR,
|
||||
\fB_RLD_LIST\fB, \fBDYLD_INSERT_LIBRARIES\fR, etc.) 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.
|
||||
@@ -266,19 +275,24 @@ As of now, \fBzzuf\fR does not really support multithreaded applications. The
|
||||
behaviour with multithreaded applications where more than one thread does file
|
||||
descriptor operations is undefined.
|
||||
.SH NOTES
|
||||
In order to intercept file and network operations and signal handlers,
|
||||
\fBzzuf\fR diverts and reimplements the following functions, which can
|
||||
be private libc symbols, too:
|
||||
In order to intercept file and network operations, signal handlers and memory
|
||||
allocations, \fBzzuf\fR diverts and reimplements the following functions,
|
||||
which can be private libc symbols, too:
|
||||
.TP
|
||||
Unix file descriptor handling:
|
||||
\fBopen\fR(), \fBlseek\fR(), \fBread\fR(), \fBaccept\fR(), \fBsocket\fR(),
|
||||
\fBmmap\fR(), \fBmunmap\fR(), \fBclose\fR()
|
||||
\fBclose\fR()
|
||||
.TP
|
||||
Standard IO streams:
|
||||
\fBfopen\fR(), \fBfreopen\fR(), \fBfseek\fR(), \fBfseeko\fR(), \fBrewind\fR(),
|
||||
\fBfread\fR(), \fBgetc\fR(), \fBfgetc\fR(), \fBfgets\fR(), \fBungetc\fR(),
|
||||
\fBfclose\fR()
|
||||
.TP
|
||||
Memory management:
|
||||
\fBmmap\fR(), \fBmunmap\fR(), \fBmalloc\fR(), \fBcalloc\fR(), \fBvalloc\fR(),
|
||||
\fBfree\fR(), \fBmemalign\fR(), \fBposix_memalign\fR(), \fBbrk\fR(),
|
||||
\fBsbrk\fR()
|
||||
.TP
|
||||
Linux-specific:
|
||||
\fBopen64\fR(), \fBlseek64\fR(), \fBmmap64\fR(), \fB_IO_getc\fR(),
|
||||
\fBgetline\fR(), \fBgetdelim\fR(), \fB__getdelim\fR()
|
||||
|
||||
@@ -44,6 +44,7 @@ int _zz_ready = 0;
|
||||
int _zz_disabled = 0;
|
||||
int _zz_hasdebug = 0;
|
||||
int _zz_signal = 0;
|
||||
int _zz_memory = 0;
|
||||
int _zz_network = 0;
|
||||
|
||||
/* Library initialisation shit */
|
||||
@@ -83,6 +84,10 @@ void _zz_init(void)
|
||||
if(tmp && *tmp == '1')
|
||||
_zz_signal = 1;
|
||||
|
||||
tmp = getenv("ZZUF_MEMORY");
|
||||
if(tmp && *tmp == '1')
|
||||
_zz_memory = 1;
|
||||
|
||||
tmp = getenv("ZZUF_NETWORK");
|
||||
if(tmp && *tmp == '1')
|
||||
_zz_network = 1;
|
||||
|
||||
@@ -39,6 +39,7 @@ extern int _zz_ready;
|
||||
extern int _zz_disabled;
|
||||
extern int _zz_hasdebug;
|
||||
extern int _zz_signal;
|
||||
extern int _zz_memory;
|
||||
extern int _zz_network;
|
||||
|
||||
/* Library initialisation shit */
|
||||
|
||||
+143
-5
@@ -22,6 +22,8 @@
|
||||
#define _GNU_SOURCE
|
||||
/* Use this to get mmap64() on glibc systems */
|
||||
#define _LARGEFILE64_SOURCE
|
||||
/* Use this to get posix_memalign */
|
||||
#define _XOPEN_SOURCE 600
|
||||
|
||||
#if defined HAVE_STDINT_H
|
||||
# include <stdint.h>
|
||||
@@ -31,7 +33,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <malloc.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#if defined HAVE_LIBC_H
|
||||
@@ -45,13 +50,27 @@
|
||||
#include "fd.h"
|
||||
|
||||
/* Library functions that we divert */
|
||||
static void * (*mmap_orig) (void *start, size_t length, int prot,
|
||||
int flags, int fd, off_t offset);
|
||||
static void * (*calloc_orig) (size_t nmemb, size_t size);
|
||||
static void * (*malloc_orig) (size_t size);
|
||||
static void (*free_orig) (void *ptr);
|
||||
static void * (*valloc_orig) (size_t size);
|
||||
static void * (*memalign_orig) (size_t boundary, size_t size);
|
||||
static int (*posix_memalign_orig) (void **memptr, size_t alignment,
|
||||
size_t size);
|
||||
static void * (*realloc_orig) (void *ptr, size_t size);
|
||||
static int (*brk_orig) (void *end_data_segment);
|
||||
static void * (*sbrk_orig) (intptr_t increment);
|
||||
|
||||
static void * (*mmap_orig) (void *start, size_t length, int prot,
|
||||
int flags, int fd, off_t offset);
|
||||
/* TODO */
|
||||
/* static void * (*mremap_orig) (void *old_address, size_t old_size,
|
||||
size_t new_size, int flags); */
|
||||
#ifdef HAVE_MMAP64
|
||||
static void * (*mmap64_orig) (void *start, size_t length, int prot,
|
||||
int flags, int fd, off64_t offset);
|
||||
static void * (*mmap64_orig) (void *start, size_t length, int prot,
|
||||
int flags, int fd, off64_t offset);
|
||||
#endif
|
||||
static int (*munmap_orig) (void *start, size_t length);
|
||||
static int (*munmap_orig) (void *start, size_t length);
|
||||
#ifdef HAVE_MAP_FD
|
||||
static kern_return_t (*map_fd_orig) (int fd, vm_offset_t offset,
|
||||
vm_offset_t *addr, boolean_t find_space,
|
||||
@@ -60,6 +79,16 @@ static kern_return_t (*map_fd_orig) (int fd, vm_offset_t offset,
|
||||
|
||||
void _zz_load_mem(void)
|
||||
{
|
||||
LOADSYM(calloc);
|
||||
LOADSYM(malloc);
|
||||
LOADSYM(free);
|
||||
LOADSYM(realloc);
|
||||
LOADSYM(valloc);
|
||||
LOADSYM(memalign);
|
||||
LOADSYM(posix_memalign);
|
||||
LOADSYM(brk);
|
||||
LOADSYM(sbrk);
|
||||
|
||||
LOADSYM(mmap);
|
||||
#ifdef HAVE_MMAP64
|
||||
LOADSYM(mmap64);
|
||||
@@ -70,6 +99,115 @@ void _zz_load_mem(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 32k of ugly static memory for programs that call us *before* we’re
|
||||
* initialised */
|
||||
uint64_t dummy_buffer[4096];
|
||||
|
||||
void *calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
void *ret;
|
||||
if(!_zz_ready)
|
||||
{
|
||||
/* Calloc says we must zero the data */
|
||||
int i = (nmemb * size + 7) / 8;
|
||||
while(i--)
|
||||
dummy_buffer[i] = 0;
|
||||
return dummy_buffer;
|
||||
}
|
||||
ret = calloc_orig(nmemb, size);
|
||||
if(ret == NULL && _zz_memory && errno == ENOMEM)
|
||||
raise(SIGKILL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *malloc(size_t size)
|
||||
{
|
||||
void *ret;
|
||||
if(!_zz_ready)
|
||||
return dummy_buffer;
|
||||
ret = malloc_orig(size);
|
||||
if(ret == NULL && _zz_memory && errno == ENOMEM)
|
||||
raise(SIGKILL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void free(void *ptr)
|
||||
{
|
||||
if(ptr == dummy_buffer)
|
||||
return;
|
||||
if(!_zz_ready)
|
||||
LOADSYM(free);
|
||||
free_orig(ptr);
|
||||
}
|
||||
|
||||
void *realloc(void *ptr, size_t size)
|
||||
{
|
||||
void *ret;
|
||||
if(ptr == dummy_buffer)
|
||||
return ptr;
|
||||
if(!_zz_ready)
|
||||
LOADSYM(realloc);
|
||||
ret = realloc_orig(ptr, size);
|
||||
if(ret == NULL && _zz_memory && errno == ENOMEM)
|
||||
raise(SIGKILL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *valloc(size_t size)
|
||||
{
|
||||
void *ret;
|
||||
if(!_zz_ready)
|
||||
LOADSYM(valloc);
|
||||
ret = valloc_orig(size);
|
||||
if(ret == NULL && _zz_memory && errno == ENOMEM)
|
||||
raise(SIGKILL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *memalign(size_t boundary, size_t size)
|
||||
{
|
||||
void *ret;
|
||||
if(!_zz_ready)
|
||||
LOADSYM(memalign);
|
||||
ret = memalign_orig(boundary, size);
|
||||
if(ret == NULL && _zz_memory && errno == ENOMEM)
|
||||
raise(SIGKILL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int posix_memalign(void **memptr, size_t alignment, size_t size)
|
||||
{
|
||||
int ret;
|
||||
if(!_zz_ready)
|
||||
LOADSYM(posix_memalign);
|
||||
ret = posix_memalign_orig(memptr, alignment, size);
|
||||
if(ret == ENOMEM && _zz_memory)
|
||||
raise(SIGKILL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int brk(void *end_data_segment)
|
||||
{
|
||||
int ret;
|
||||
if(!_zz_ready)
|
||||
LOADSYM(brk);
|
||||
ret = brk_orig(end_data_segment);
|
||||
if(ret == -1 && _zz_memory && errno == ENOMEM)
|
||||
raise(SIGKILL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *sbrk(intptr_t increment)
|
||||
{
|
||||
void *ret;
|
||||
if(!_zz_ready)
|
||||
LOADSYM(sbrk);
|
||||
ret = sbrk_orig(increment);
|
||||
if(ret == (void *)-1 && _zz_memory && errno == ENOMEM)
|
||||
raise(SIGKILL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Table used for mmap() and munmap() */
|
||||
void **maps = NULL;
|
||||
int nbmaps = 0;
|
||||
|
||||
+25
-5
@@ -36,6 +36,8 @@
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "libzzuf.h"
|
||||
#include "random.h"
|
||||
@@ -80,6 +82,7 @@ static int quiet = 0;
|
||||
static int maxbytes = -1;
|
||||
static int md5 = 0;
|
||||
static int checkexit = 0;
|
||||
static int maxmem = -1;
|
||||
static double maxtime = -1.0;
|
||||
|
||||
#define ZZUF_FD_SET(fd, p_fdset, maxfd) \
|
||||
@@ -119,6 +122,7 @@ int main(int argc, char *argv[])
|
||||
{ "stdin", 0, NULL, 'i' },
|
||||
{ "include", 1, NULL, 'I' },
|
||||
{ "md5", 0, NULL, 'm' },
|
||||
{ "max-memory", 1, NULL, 'M' },
|
||||
{ "network", 0, NULL, 'n' },
|
||||
{ "protect", 1, NULL, 'P' },
|
||||
{ "quiet", 0, NULL, 'q' },
|
||||
@@ -131,11 +135,11 @@ int main(int argc, char *argv[])
|
||||
{ "help", 0, NULL, 'h' },
|
||||
{ "version", 0, NULL, 'v' },
|
||||
};
|
||||
int c = getopt_long(argc, argv, "B:cC:dE:F:iI:mnP:qr:R:s:ST:xhv",
|
||||
int c = getopt_long(argc, argv, "B:cC:dE:F:iI:mM:nP:qr:R:s:ST:xhv",
|
||||
long_options, &option_index);
|
||||
# else
|
||||
# define MOREINFO "Try `%s -h' for more information.\n"
|
||||
int c = getopt(argc, argv, "B:cC:dE:F:iI:mnP:qr:R:s:ST:xhv");
|
||||
int c = getopt(argc, argv, "B:cC:dE:F:iI:mM:nP:qr:R:s:ST:xhv");
|
||||
# endif
|
||||
if(c == -1)
|
||||
break;
|
||||
@@ -181,6 +185,10 @@ int main(int argc, char *argv[])
|
||||
case 'm': /* --md5 */
|
||||
md5 = 1;
|
||||
break;
|
||||
case 'M': /* --max-memory */
|
||||
setenv("ZZUF_MEMORY", "1", 1);
|
||||
maxmem = atoi(optarg);
|
||||
break;
|
||||
case 'n': /* --network */
|
||||
setenv("ZZUF_NETWORK", "1", 1);
|
||||
break;
|
||||
@@ -424,6 +432,14 @@ static void spawn_child(char **argv)
|
||||
return;
|
||||
case 0:
|
||||
/* We’re the child */
|
||||
if(maxmem >= 0)
|
||||
{
|
||||
struct rlimit rlim;
|
||||
rlim.rlim_cur = maxmem * 1000000;
|
||||
rlim.rlim_max = maxmem * 1000000;
|
||||
setrlimit(RLIMIT_AS, &rlim);
|
||||
}
|
||||
|
||||
for(j = 0; j < 3; j++)
|
||||
{
|
||||
close(fd[j][0]);
|
||||
@@ -528,8 +544,10 @@ static void clean_children(void)
|
||||
}
|
||||
else if(WIFSIGNALED(status))
|
||||
{
|
||||
fprintf(stdout, "zzuf[seed=%i]: signal %i\n",
|
||||
child_list[i].seed, WTERMSIG(status));
|
||||
fprintf(stdout, "zzuf[seed=%i]: signal %i%s\n",
|
||||
child_list[i].seed, WTERMSIG(status),
|
||||
(WTERMSIG(status) == SIGKILL && maxmem >= 0) ?
|
||||
" (memory exceeded?)" : "");
|
||||
crashes++;
|
||||
}
|
||||
|
||||
@@ -666,7 +684,7 @@ static void usage(void)
|
||||
{
|
||||
printf("Usage: zzuf [-cdimnqSx] [-r ratio] [-s seed | -s start:stop]\n");
|
||||
printf(" [-F forks] [-C crashes] [-B bytes] [-T seconds]\n");
|
||||
printf(" [-P protect] [-R refuse]\n");
|
||||
printf(" [-M bytes] [-P protect] [-R refuse]\n");
|
||||
printf(" [-I include] [-E exclude] [PROGRAM [ARGS]...]\n");
|
||||
# ifdef HAVE_GETOPT_LONG
|
||||
printf(" zzuf -h | --help\n");
|
||||
@@ -688,6 +706,7 @@ static void usage(void)
|
||||
printf(" -i, --stdin fuzz standard input\n");
|
||||
printf(" -I, --include <regex> only fuzz files matching <regex>\n");
|
||||
printf(" -m, --md5 compute the output's MD5 hash\n");
|
||||
printf(" -M, --max-memory <n> maximum child virtual memory size in MB\n");
|
||||
printf(" -n, --network fuzz network input\n");
|
||||
printf(" -P, --protect <list> protect bytes and characters in <list>\n");
|
||||
printf(" -q, --quiet do not print children's messages\n");
|
||||
@@ -710,6 +729,7 @@ static void usage(void)
|
||||
printf(" -i fuzz standard input\n");
|
||||
printf(" -I <regex> only fuzz files matching <regex>\n");
|
||||
printf(" -m compute the output's MD5 hash\n");
|
||||
printf(" -M maximum child virtual memory size in MB\n");
|
||||
printf(" -n fuzz network input\n");
|
||||
printf(" -P <list> protect bytes and characters in <list>\n");
|
||||
printf(" -q do not print the fuzzed application's messages\n");
|
||||
|
||||
Reference in New Issue
Block a user