Files
zzuf/src/lib-fd.c
Sam Hocevar 351b447bfa * Added enough autoconf checks and #ifdefs so that libzzuf builds on Win32.
zzuf itself doesn't build yet, though.
2007-01-18 00:21:07 +00:00

503 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* zzuf - general purpose fuzzer
* Copyright (c) 2006, 2007 Sam Hocevar <sam@zoy.org>
* 2007 Rémi Denis-Courmont <rdenis#simphalempin:com>
* 2007 Clément Stenac <zorglub#diwi:org>
* 2007 Dominik Kuhlen <dominik.kuhlen#gmit-gmbh:de>
* 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.
*/
/*
* load-fd.c: loaded file descriptor functions
*/
#include "config.h"
/* Need this for RTLD_NEXT */
#define _GNU_SOURCE
/* Use this to get lseek64() on glibc systems */
#define _LARGEFILE64_SOURCE
#if defined HAVE_STDINT_H
# include <stdint.h>
#elif defined HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#if defined HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#if defined HAVE_SYS_UIO_H
# include <sys/uio.h>
#endif
#include <unistd.h>
#include <fcntl.h>
#include <stdarg.h>
#if defined HAVE_AIO_H
# include <aio.h>
#endif
#include "libzzuf.h"
#include "lib-load.h"
#include "debug.h"
#include "fuzz.h"
#include "fd.h"
#if defined HAVE_SOCKLEN_T
# define SOCKLEN_T socklen_t
#else
# define SOCKLEN_T int
#endif
/* Local prototypes */
#if defined HAVE_READV || defined HAVE_RECVMSG
static void fuzz_iovec (int fd, const struct iovec *iov, ssize_t ret);
#endif
static void offset_check (int fd);
/* Library functions that we divert */
static int (*open_orig) (const char *file, int oflag, ...);
#if defined HAVE_OPEN64
static int (*open64_orig) (const char *file, int oflag, ...);
#endif
#if defined HAVE_ACCEPT
static int (*accept_orig) (int sockfd, struct sockaddr *addr,
SOCKLEN_T *addrlen);
#endif
#if defined HAVE_SOCKET
static int (*socket_orig) (int domain, int type, int protocol);
#endif
#if defined HAVE_RECV
static int (*recv_orig) (int s, void *buf, size_t len, int flags);
#endif
#if defined HAVE_RECVFROM
static int (*recvfrom_orig)(int s, void *buf, size_t len, int flags,
struct sockaddr *from, SOCKLEN_T *fromlen);
#endif
#if defined HAVE_RECVMSG
static int (*recvmsg_orig) (int s, struct msghdr *hdr, int flags);
#endif
#if defined READ_USES_SSIZE_T
static ssize_t (*read_orig) (int fd, void *buf, size_t count);
#else
static int (*read_orig) (int fd, void *buf, unsigned int count);
#endif
#if defined HAVE_READV
static ssize_t (*readv_orig) (int fd, const struct iovec *iov, int count);
#endif
#if defined HAVE_PREAD
static ssize_t (*pread_orig) (int fd, void *buf, size_t count, off_t offset);
#endif
#if defined HAVE_AIO_READ
static int (*aio_read_orig) (struct aiocb *aiocbp);
static ssize_t (*aio_return_orig) (struct aiocb *aiocbp);
#endif
static off_t (*lseek_orig) (int fd, off_t offset, int whence);
#if defined HAVE_LSEEK64
static off64_t (*lseek64_orig) (int fd, off64_t offset, int whence);
#endif
static int (*close_orig) (int fd);
#define OPEN(fn) \
do \
{ \
int mode = 0; \
LOADSYM(fn); \
if(oflag & O_CREAT) \
{ \
va_list va; \
va_start(va, oflag); \
mode = va_arg(va, int); \
va_end(va); \
ret = ORIG(fn)(file, oflag, mode); \
} \
else \
{ \
ret = ORIG(fn)(file, oflag); \
} \
if(!_zz_ready || _zz_islocked(-1)) \
return ret; \
if(ret >= 0 \
&& ((oflag & (O_RDONLY | O_RDWR | O_WRONLY)) != O_WRONLY) \
&& _zz_mustwatch(file)) \
{ \
if(oflag & O_CREAT) \
debug("%s(\"%s\", %i, %i) = %i", \
__func__, file, oflag, mode, ret); \
else \
debug("%s(\"%s\", %i) = %i", __func__, file, oflag, ret); \
_zz_register(ret); \
} \
} while(0)
int open(const char *file, int oflag, ...)
{
int ret; OPEN(open); return ret;
}
#if defined HAVE_OPEN64
int open64(const char *file, int oflag, ...)
{
int ret; OPEN(open64); return ret;
}
#endif
#if defined HAVE_ACCEPT
int accept(int sockfd, struct sockaddr *addr, SOCKLEN_T *addrlen)
{
int ret;
LOADSYM(accept);
ret = accept_orig(sockfd, addr, addrlen);
if(!_zz_ready || _zz_islocked(-1) || !_zz_network)
return ret;
if(ret >= 0)
{
debug("%s(%i, %p, %p) = %i", __func__, sockfd, addr, addrlen, ret);
_zz_register(ret);
}
return ret;
}
#endif
#if defined HAVE_SOCKET
int socket(int domain, int type, int protocol)
{
int ret;
LOADSYM(socket);
ret = socket_orig(domain, type, protocol);
if(!_zz_ready || _zz_islocked(-1) || !_zz_network)
return ret;
if(ret >= 0)
{
debug("%s(%i, %i, %i) = %i", __func__, domain, type, protocol, ret);
_zz_register(ret);
}
return ret;
}
#endif
#if defined HAVE_RECV
int recv(int s, void *buf, size_t len, int flags)
{
int ret;
LOADSYM(recv);
ret = recv_orig(s, buf, len, flags);
if(!_zz_ready || !_zz_iswatched(s) || _zz_islocked(s))
return ret;
if(ret > 0)
{
char *b = buf;
_zz_fuzz(s, buf, ret);
_zz_addpos(s, ret);
if(ret >= 4)
debug("%s(%i, %p, %li, 0x%x) = %i \"%c%c%c%c...", __func__,
s, buf, (long int)len, flags, ret, b[0], b[1], b[2], b[3]);
else
debug("%s(%i, %p, %li, 0x%x) = %i \"%c...", __func__,
s, buf, (long int)len, flags, ret, b[0]);
}
else
debug("%s(%i, %p, %li, 0x%x) = %i", __func__,
s, buf, (long int)len, flags, ret);
return ret;
}
#endif
#if defined HAVE_RECVFROM
int recvfrom(int s, void *buf, size_t len, int flags,
struct sockaddr *from, SOCKLEN_T *fromlen)
{
int ret;
LOADSYM(recvfrom);
ret = recvfrom_orig(s, buf, len, flags, from, fromlen);
if(!_zz_ready || !_zz_iswatched(s) || _zz_islocked(s))
return ret;
if(ret > 0)
{
char *b = buf;
_zz_fuzz(s, buf, ret);
_zz_addpos(s, ret);
if(ret >= 4)
debug("%s(%i, %p, %li, 0x%x, %p, %p) = %i \"%c%c%c%c...", __func__,
s, buf, (long int)len, flags, from, fromlen, ret,
b[0], b[1], b[2], b[3]);
else
debug("%s(%i, %p, %li, 0x%x, %p, %p) = %i \"%c...", __func__,
s, buf, (long int)len, flags, from, fromlen, ret, b[0]);
}
else
debug("%s(%i, %p, %li, 0x%x, %p, %p) = %i", __func__,
s, buf, (long int)len, flags, from, fromlen, ret);
return ret;
}
#endif
#if defined HAVE_RECVMSG
int recvmsg(int s, struct msghdr *hdr, int flags)
{
ssize_t ret;
LOADSYM(recvmsg);
ret = recvmsg_orig(s, hdr, flags);
if(!_zz_ready || !_zz_iswatched(s) || _zz_islocked(s))
return ret;
fuzz_iovec(s, hdr->msg_iov, ret);
debug("%s(%i, %p, %x) = %li", __func__, s, hdr, flags, (long int)ret);
return ret;
}
#endif
#if defined READ_USES_SSIZE_T
ssize_t read(int fd, void *buf, size_t count)
#else
int read(int fd, void *buf, unsigned int count)
#endif
{
int ret;
LOADSYM(read);
ret = read_orig(fd, buf, count);
if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd))
return ret;
if(ret > 0)
{
char *b = buf;
_zz_fuzz(fd, buf, ret);
_zz_addpos(fd, ret);
if(ret >= 4)
debug("%s(%i, %p, %li) = %i \"%c%c%c%c...", __func__, fd, buf,
(long int)count, ret, b[0], b[1], b[2], b[3]);
else
debug("%s(%i, %p, %li) = %i \"%c...", __func__, fd, buf,
(long int)count, ret, b[0]);
}
else
debug("%s(%i, %p, %li) = %i", __func__, fd, buf, (long int)count, ret);
offset_check(fd);
return ret;
}
#if defined HAVE_READV
ssize_t readv(int fd, const struct iovec *iov, int count)
{
ssize_t ret;
LOADSYM(readv);
ret = readv_orig(fd, iov, count);
if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd))
return ret;
fuzz_iovec(fd, iov, ret);
debug("%s(%i, %p, %i) = %li", __func__, fd, iov, count, (long int)ret);
offset_check(fd);
return ret;
}
#endif
#if defined HAVE_PREAD
ssize_t pread(int fd, void *buf, size_t count, off_t offset)
{
int ret;
LOADSYM(pread);
ret = pread_orig(fd, buf, count, offset);
if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd))
return ret;
if(ret > 0)
{
long int curoff = _zz_getpos(fd);
char *b = buf;
_zz_setpos(fd, offset);
_zz_fuzz(fd, buf, ret);
_zz_setpos(fd, curoff);
if(ret >= 4)
debug("%s(%i, %p, %li, %li) = %i \"%c%c%c%c...", __func__, fd, buf,
(long int)count, (long int)offset, ret,
b[0], b[1], b[2], b[3]);
else
debug("%s(%i, %p, %li, %li) = %i \"%c...", __func__, fd, buf,
(long int)count, (long int)offset, ret, b[0]);
}
else
debug("%s(%i, %p, %li, %li) = %i", __func__, fd, buf,
(long int)count, (long int)offset, ret);
return ret;
}
#endif
#define LSEEK(fn, off_t) \
do \
{ \
LOADSYM(fn); \
ret = ORIG(fn)(fd, offset, whence); \
if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd)) \
return ret; \
debug("%s(%i, %lli, %i) = %lli", __func__, fd, \
(long long int)offset, whence, (long long int)ret); \
if(ret != (off_t)-1) \
_zz_setpos(fd, ret); \
} while(0)
off_t lseek(int fd, off_t offset, int whence)
{
off_t ret;
LSEEK(lseek, off_t);
return ret;
}
#if defined HAVE_LSEEK64
off64_t lseek64(int fd, off64_t offset, int whence)
{
off64_t ret;
LSEEK(lseek64, off64_t);
return ret;
}
#endif
#if defined HAVE_AIO_READ
int aio_read(struct aiocb *aiocbp)
{
int ret;
int fd = aiocbp->aio_fildes;
LOADSYM(aio_read);
if(!_zz_ready || !_zz_iswatched(fd))
return aio_read_orig(aiocbp);
_zz_lock(fd);
ret = aio_read_orig(aiocbp);
debug("%s({%i, %i, %i, %p, %li, ..., %li}) = %i", __func__,
fd, aiocbp->aio_lio_opcode, aiocbp->aio_reqprio, aiocbp->aio_buf,
(long int)aiocbp->aio_nbytes, (long int)aiocbp->aio_offset, ret);
return ret;
}
ssize_t aio_return(struct aiocb *aiocbp)
{
ssize_t ret;
int fd = aiocbp->aio_fildes;
LOADSYM(aio_return);
if(!_zz_ready || !_zz_iswatched(fd))
return aio_return_orig(aiocbp);
ret = aio_return_orig(aiocbp);
_zz_unlock(fd);
/* FIXME: make sure were actually *reading* */
if(ret > 0)
{
_zz_setpos(fd, aiocbp->aio_offset);
_zz_fuzz(fd, aiocbp->aio_buf, ret);
_zz_addpos(fd, ret);
}
debug("%s({%i, %i, %i, %p, %li, ..., %li}) = %li", __func__,
fd, aiocbp->aio_lio_opcode, aiocbp->aio_reqprio, aiocbp->aio_buf,
(long int)aiocbp->aio_nbytes, (long int)aiocbp->aio_offset,
(long int)ret);
return ret;
}
#endif
int close(int fd)
{
int ret;
/* Hey, its our debug channel! Silently pretend we closed it. */
if(fd == DEBUG_FILENO)
return 0;
LOADSYM(close);
ret = close_orig(fd);
if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd))
return ret;
debug("%s(%i) = %i", __func__, fd, ret);
_zz_unregister(fd);
return ret;
}
/* XXX: the following functions are local */
#if defined HAVE_READV || defined HAVE_RECVMSG
static void fuzz_iovec(int fd, const struct iovec *iov, ssize_t ret)
{
/* NOTE: We assume that iov countains at least <ret> bytes. */
while(ret > 0)
{
void *b = iov->iov_base;
size_t len = iov->iov_len;
if(len > (size_t)ret)
len = ret;
_zz_fuzz(fd, b, len);
_zz_addpos(fd, len);
iov++;
ret -= len;
}
}
#endif
static void offset_check(int fd)
{
/* Sanity check, can be OK though (for instance with a character device) */
#if defined HAVE_LSEEK64
off64_t ret;
LOADSYM(lseek64);
ret = lseek64_orig(fd, 0, SEEK_CUR);
#else
off_t ret;
LOADSYM(lseek);
ret = lseek_orig(fd, 0, SEEK_CUR);
#endif
if(ret != -1 && ret != _zz_getpos(fd))
debug("warning: offset inconsistency");
}