396 lines
8.1 KiB
C
396 lines
8.1 KiB
C
/*
|
||
* zzuf - general purpose fuzzer
|
||
* Copyright (c) 2006-2007 Sam Hocevar <sam@zoy.org>
|
||
* 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 <stdint.h>
|
||
#elif defined HAVE_INTTYPES_H
|
||
# include <inttypes.h>
|
||
#endif
|
||
#include <stdlib.h>
|
||
#if defined HAVE_REGEX_H
|
||
# include <regex.h>
|
||
#endif
|
||
#include <string.h>
|
||
#include <math.h>
|
||
|
||
#include "debug.h"
|
||
#include "libzzuf.h"
|
||
#include "fd.h"
|
||
#include "fuzz.h"
|
||
#include "ranges.h"
|
||
|
||
/* Regex stuff */
|
||
#if defined HAVE_REGEX_H
|
||
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];
|
||
|
||
/* 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
|
||
* at the same time, a bigger array is malloc()ed and replaces the static one.
|
||
*/
|
||
#define STATIC_FILES 32
|
||
static struct files
|
||
{
|
||
int managed, locked, active;
|
||
int64_t pos;
|
||
/* Public stuff */
|
||
struct fuzz fuzz;
|
||
}
|
||
*files, static_files[STATIC_FILES];
|
||
static int *fds, static_fds[STATIC_FILES];
|
||
static int maxfd, nfiles;
|
||
|
||
/* Create lock. This lock variable is used to disable file descriptor
|
||
* creation wrappers. For instance on Mac OS X, fopen() calls open()
|
||
* and we don’t want open() to do any zzuf-related stuff: fopen() takes
|
||
* care of everything. */
|
||
static int create_lock = 0;
|
||
|
||
static int32_t seed = DEFAULT_SEED;
|
||
static double minratio = DEFAULT_RATIO;
|
||
static double maxratio = DEFAULT_RATIO;
|
||
static int autoinc = 0;
|
||
|
||
void _zz_include(char const *regex)
|
||
{
|
||
#if defined HAVE_REGEX_H
|
||
if(regcomp(&re_include, regex, REG_EXTENDED) == 0)
|
||
has_include = 1;
|
||
#else
|
||
(void)regex;
|
||
#endif
|
||
}
|
||
|
||
void _zz_exclude(char const *regex)
|
||
{
|
||
#if defined HAVE_REGEX_H
|
||
if(regcomp(&re_exclude, regex, REG_EXTENDED) == 0)
|
||
has_exclude = 1;
|
||
#else
|
||
(void)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);
|
||
}
|
||
|
||
void _zz_setseed(int32_t s)
|
||
{
|
||
seed = s;
|
||
}
|
||
|
||
void _zz_setratio(double r0, double r1)
|
||
{
|
||
if(r0 == 0.0 && r1 == 0.0)
|
||
{
|
||
maxratio = minratio = 0.0;
|
||
return;
|
||
}
|
||
|
||
minratio = r0 < MIN_RATIO ? MIN_RATIO : r0 > MAX_RATIO ? MAX_RATIO : r0;
|
||
maxratio = r1 < MIN_RATIO ? MIN_RATIO : r1 > MAX_RATIO ? MAX_RATIO : r1;
|
||
if(maxratio < minratio)
|
||
maxratio = minratio;
|
||
}
|
||
|
||
double _zz_getratio(void)
|
||
{
|
||
uint8_t const shuffle[16] =
|
||
{ 0, 12, 2, 10,
|
||
14, 8, 15, 7,
|
||
9, 13, 3, 6,
|
||
4, 1, 11, 5 };
|
||
uint16_t rate;
|
||
double min, max, cur;
|
||
|
||
if(minratio == maxratio)
|
||
return minratio; /* this also takes care of 0.0 */
|
||
|
||
rate = shuffle[seed & 0xf] << 12;
|
||
rate |= (seed & 0xf0) << 4;
|
||
rate |= (seed & 0xf00) >> 4;
|
||
rate |= (seed & 0xf000) >> 12;
|
||
|
||
min = log(minratio);
|
||
max = log(maxratio);
|
||
|
||
cur = min + (max - min) * rate / 0xffff;
|
||
|
||
return exp(cur);
|
||
}
|
||
|
||
void _zz_setautoinc(void)
|
||
{
|
||
autoinc = 1;
|
||
}
|
||
|
||
void _zz_fd_init(void)
|
||
{
|
||
/* We start with 32 file descriptors. This is to reduce the number of
|
||
* calls to malloc() that we do, so we get better chances that memory
|
||
* corruption errors are reproducible */
|
||
files = static_files;
|
||
for(nfiles = 0; nfiles < 32; nfiles++)
|
||
files[nfiles].managed = 0;
|
||
|
||
fds = static_fds;
|
||
for(maxfd = 0; maxfd < 32; 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. */
|
||
}
|
||
|
||
#if defined HAVE_REGEX_H
|
||
if(has_include)
|
||
regfree(&re_include);
|
||
if(has_exclude)
|
||
regfree(&re_exclude);
|
||
#endif
|
||
|
||
if(files != static_files)
|
||
free(files);
|
||
if(fds != static_fds)
|
||
free(fds);
|
||
if(list != static_list)
|
||
free(list);
|
||
if(ports != static_ports)
|
||
free(ports);
|
||
}
|
||
|
||
int _zz_mustwatch(char const *file)
|
||
{
|
||
#if defined HAVE_REGEX_H
|
||
if(has_include && regexec(&re_include, file, 0, NULL, 0) == REG_NOMATCH)
|
||
return 0; /* not included: ignore */
|
||
|
||
if(has_exclude && regexec(&re_exclude, file, 0, NULL, 0) != REG_NOMATCH)
|
||
return 0; /* excluded: ignore */
|
||
#else
|
||
(void)file;
|
||
#endif
|
||
|
||
return 1; /* default */
|
||
}
|
||
|
||
int _zz_iswatched(int fd)
|
||
{
|
||
if(fd < 0 || fd >= maxfd || fds[fd] == -1)
|
||
return 0;
|
||
|
||
return 1;
|
||
}
|
||
|
||
int _zz_portwatched(int port)
|
||
{
|
||
if(!ports)
|
||
return 1;
|
||
|
||
return _zz_isinrange(port, ports);
|
||
}
|
||
|
||
void _zz_register(int fd)
|
||
{
|
||
int i;
|
||
|
||
if(fd < 0 || fd > 65535 || (fd < maxfd && fds[fd] != -1))
|
||
return;
|
||
|
||
#if 0
|
||
if(autoinc)
|
||
debug("using seed %li", (long int)seed);
|
||
#endif
|
||
|
||
/* If filedescriptor is outside our bounds */
|
||
while(fd >= maxfd)
|
||
{
|
||
if(fds == static_fds)
|
||
{
|
||
fds = malloc(2 * maxfd * sizeof(*fds));
|
||
memcpy(fds, static_fds, maxfd * sizeof(*fds));
|
||
}
|
||
else
|
||
fds = realloc(fds, 2 * maxfd * sizeof(*fds));
|
||
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++;
|
||
if(files == static_files)
|
||
{
|
||
files = malloc(nfiles * sizeof(*files));
|
||
memcpy(files, static_files, nfiles * sizeof(*files));
|
||
}
|
||
else
|
||
files = realloc(files, nfiles * sizeof(*files));
|
||
}
|
||
|
||
files[i].managed = 1;
|
||
files[i].locked = 0;
|
||
files[i].pos = 0;
|
||
files[i].fuzz.seed = seed;
|
||
files[i].fuzz.ratio = _zz_getratio();
|
||
files[i].fuzz.cur = -1;
|
||
#if defined HAVE_FGETLN
|
||
files[i].fuzz.tmp = NULL;
|
||
#endif
|
||
files[i].fuzz.uflag = 0;
|
||
|
||
/* Check whether we should ignore the fd */
|
||
if(list)
|
||
{
|
||
static int idx = 0;
|
||
|
||
files[i].active = _zz_isinrange(++idx, list);
|
||
}
|
||
else
|
||
files[i].active = 1;
|
||
|
||
if(autoinc)
|
||
seed++;
|
||
|
||
fds[fd] = i;
|
||
}
|
||
|
||
void _zz_unregister(int fd)
|
||
{
|
||
if(fd < 0 || fd >= maxfd || fds[fd] == -1)
|
||
return;
|
||
|
||
files[fds[fd]].managed = 0;
|
||
#if defined HAVE_FGETLN
|
||
if(files[fds[fd]].fuzz.tmp)
|
||
free(files[fds[fd]].fuzz.tmp);
|
||
#endif
|
||
|
||
fds[fd] = -1;
|
||
}
|
||
|
||
void _zz_lock(int fd)
|
||
{
|
||
if(fd < -1 || fd >= maxfd || fds[fd] == -1)
|
||
return;
|
||
|
||
if(fd == -1)
|
||
create_lock++;
|
||
else
|
||
files[fds[fd]].locked++;
|
||
}
|
||
|
||
void _zz_unlock(int fd)
|
||
{
|
||
if(fd < -1 || fd >= maxfd || fds[fd] == -1)
|
||
return;
|
||
|
||
if(fd == -1)
|
||
create_lock--;
|
||
else
|
||
files[fds[fd]].locked--;
|
||
}
|
||
|
||
int _zz_islocked(int fd)
|
||
{
|
||
if(fd < -1 || fd >= maxfd || fds[fd] == -1)
|
||
return 0;
|
||
|
||
if(fd == -1)
|
||
return create_lock;
|
||
else
|
||
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)
|
||
return 0;
|
||
|
||
return files[fds[fd]].pos;
|
||
}
|
||
|
||
void _zz_setpos(int fd, int64_t pos)
|
||
{
|
||
if(fd < 0 || fd >= maxfd || fds[fd] == -1)
|
||
return;
|
||
|
||
files[fds[fd]].pos = pos;
|
||
}
|
||
|
||
void _zz_addpos(int fd, int64_t 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;
|
||
}
|
||
|