source: zzuf/trunk/src/load-fd.c @ 1677

Last change on this file since 1677 was 1677, checked in by Sam Hocevar, 14 years ago
  • Don't do the offset sanity check on non-seekable devices.
  • Property svn:keywords set to Id
File size: 6.5 KB
Line 
1/*
2 *  zzuf - general purpose fuzzer
3 *  Copyright (c) 2006, 2007 Sam Hocevar <sam@zoy.org>
4 *                2007 Rémi Denis-Courmont <rdenis#simphalempin:com>
5 *                All Rights Reserved
6 *
7 *  $Id: load-fd.c 1677 2007-01-16 14:06:57Z sam $
8 *
9 *  This program is free software. It comes without any warranty, to
10 *  the extent permitted by applicable law. You can redistribute it
11 *  and/or modify it under the terms of the Do What The Fuck You Want
12 *  To Public License, Version 2, as published by Sam Hocevar. See
13 *  http://sam.zoy.org/wtfpl/COPYING for more details.
14 */
15
16/*
17 *  load-fd.c: loaded file descriptor functions
18 */
19
20#include "config.h"
21
22/* Need this for RTLD_NEXT */
23#define _GNU_SOURCE
24/* Use this to get lseek64() on glibc systems */
25#define _LARGEFILE64_SOURCE
26
27#if defined HAVE_STDINT_H
28#   include <stdint.h>
29#elif defined HAVE_INTTYPES_H
30#   include <inttypes.h>
31#endif
32#include <stdlib.h>
33#include <string.h>
34#include <dlfcn.h>
35
36#include <sys/types.h>
37#include <sys/socket.h>
38#include <sys/uio.h>
39#include <unistd.h>
40#include <fcntl.h>
41#include <stdarg.h>
42
43#include "libzzuf.h"
44#include "debug.h"
45#include "fuzz.h"
46#include "load.h"
47#include "fd.h"
48
49#ifdef HAVE_SOCKLEN_T
50#   define SOCKLEN_T socklen_t
51#else
52#   define SOCKLEN_T int
53#endif
54
55/* Library functions that we divert */
56static int     (*open_orig)    (const char *file, int oflag, ...);
57#ifdef HAVE_OPEN64
58static int     (*open64_orig)  (const char *file, int oflag, ...);
59#endif
60static int     (*accept_orig)  (int sockfd, struct sockaddr *addr,
61                                SOCKLEN_T *addrlen);
62static int     (*socket_orig)  (int domain, int type, int protocol);
63static ssize_t (*read_orig)    (int fd, void *buf, size_t count);
64static ssize_t (*readv_orig)   (int fd, const struct iovec *iov, int count);
65static off_t   (*lseek_orig)   (int fd, off_t offset, int whence);
66#ifdef HAVE_LSEEK64
67static off64_t (*lseek64_orig) (int fd, off64_t offset, int whence);
68#endif
69static int     (*close_orig)   (int fd);
70
71
72void _zz_load_fd(void)
73{
74    LOADSYM(open);
75#ifdef HAVE_OPEN64
76    LOADSYM(open64);
77#endif
78    LOADSYM(accept);
79    LOADSYM(socket);
80    LOADSYM(read);
81    LOADSYM(lseek);
82#ifdef HAVE_LSEEK64
83    LOADSYM(lseek64);
84#endif
85    LOADSYM(close);
86}
87
88#define OPEN(fn) \
89    do \
90    { \
91        int mode = 0; \
92        LOADSYM(fn); \
93        if(oflag & O_CREAT) \
94        { \
95            va_list va; \
96            va_start(va, oflag); \
97            mode = va_arg(va, int); \
98            va_end(va); \
99            ret = ORIG(fn)(file, oflag, mode); \
100        } \
101        else \
102        { \
103            ret = ORIG(fn)(file, oflag); \
104        } \
105        if(!_zz_ready || _zz_disabled) \
106            return ret; \
107        if(ret >= 0 \
108            && ((oflag & (O_RDONLY | O_RDWR | O_WRONLY)) != O_WRONLY) \
109            && _zz_mustwatch(file)) \
110        { \
111            if(oflag & O_CREAT) \
112                debug(STR(fn) "(\"%s\", %i, %i) = %i", \
113                      file, oflag, mode, ret); \
114            else \
115                debug(STR(fn) "(\"%s\", %i) = %i", file, oflag, ret); \
116            _zz_register(ret); \
117        } \
118    } while(0)
119
120int open(const char *file, int oflag, ...)
121{
122    int ret; OPEN(open); return ret;
123}
124
125#ifdef HAVE_OPEN64
126int open64(const char *file, int oflag, ...)
127{
128    int ret; OPEN(open64); return ret;
129}
130#endif
131
132int accept(int sockfd, struct sockaddr *addr, SOCKLEN_T *addrlen)
133{
134    int ret;
135
136    LOADSYM(accept);
137    ret = accept_orig(sockfd, addr, addrlen);
138    if(!_zz_ready || _zz_disabled || !_zz_network)
139        return ret;
140
141    if(ret >= 0)
142    {
143        debug("accept(%i, %p, %p) = %i", sockfd, addr, addrlen, ret);
144        _zz_register(ret);
145    }
146
147    return ret;
148}
149
150int socket(int domain, int type, int protocol)
151{
152    int ret;
153
154    LOADSYM(socket);
155    ret = socket_orig(domain, type, protocol);
156    if(!_zz_ready || _zz_disabled || !_zz_network)
157        return ret;
158
159    if(ret >= 0)
160    {
161        debug("socket(%i, %i, %i) = %i", domain, type, protocol, ret);
162        _zz_register(ret);
163    }
164
165    return ret;
166}
167
168static void offset_check(int fd)
169{
170    /* Sanity check, can be OK though (for instance with a character device) */
171#ifdef HAVE_LSEEK64
172    off64_t ret = lseek64_orig(fd, 0, SEEK_CUR);
173#else
174    off_t ret = lseek_orig(fd, 0, SEEK_CUR);
175#endif
176    if(ret != -1 && ret != _zz_getpos(fd))
177        debug("warning: offset inconsistency");
178}
179
180ssize_t read(int fd, void *buf, size_t count)
181{
182    int ret;
183
184    LOADSYM(read);
185    ret = read_orig(fd, buf, count);
186    if(!_zz_ready || !_zz_iswatched(fd) || _zz_disabled)
187        return ret;
188
189    if(ret > 0)
190    {
191        char *b = buf;
192
193        _zz_fuzz(fd, buf, ret);
194        _zz_addpos(fd, ret);
195
196        if(ret >= 4)
197            debug("read(%i, %p, %li) = %i \"%c%c%c%c...", fd, buf,
198                  (long int)count, ret, b[0], b[1], b[2], b[3]);
199        else
200            debug("read(%i, %p, %li) = %i \"%c...", fd, buf,
201                  (long int)count, ret, b[0]);
202    }
203    else
204        debug("read(%i, %p, %li) = %i", fd, buf, (long int)count, ret);
205
206    offset_check(fd);
207    return ret;
208}
209
210ssize_t readv(int fd, const struct iovec *iov, int count)
211{
212    ssize_t ret;
213
214    LOADSYM(readv);
215    ret = readv_orig(fd, iov, count);
216    if(!_zz_ready || !_zz_iswatched(fd) || _zz_disabled)
217        return ret;
218
219    debug("readv(%i, %p, %i) = %li", fd, iov, count, (long int)ret);
220
221    while(ret > 0)
222    {
223        void *b = iov->iov_base;
224        size_t len = iov->iov_len;
225
226        if(len > (size_t)ret)
227            len = ret;
228
229        _zz_fuzz(fd, b, len);
230        _zz_addpos(fd, len);
231
232        iov++;
233        ret -= len;
234    }
235
236    offset_check(fd);
237    return ret;
238}
239
240#define LSEEK(fn, off_t) \
241    do \
242    { \
243        LOADSYM(fn); \
244        ret = ORIG(fn)(fd, offset, whence); \
245        if(!_zz_ready || !_zz_iswatched(fd) || _zz_disabled) \
246            return ret; \
247        debug(STR(fn)"(%i, %lli, %i) = %lli", \
248              fd, (long long int)offset, whence, (long long int)ret); \
249        if(ret != (off_t)-1) \
250            _zz_setpos(fd, ret); \
251    } while(0)
252
253off_t lseek(int fd, off_t offset, int whence)
254{
255    off_t ret;
256    LSEEK(lseek, off_t);
257    return ret;
258}
259
260#ifdef HAVE_LSEEK64
261off64_t lseek64(int fd, off64_t offset, int whence)
262{
263    off64_t ret;
264    LSEEK(lseek64, off64_t);
265    return ret;
266}
267#endif
268
269int close(int fd)
270{
271    int ret;
272
273    LOADSYM(close);
274
275    /* Hey, it’s our debug channel! Silently pretend we closed it. */
276    if(fd == DEBUG_FILENO)
277        return 0;
278
279    ret = close_orig(fd);
280    if(!_zz_ready || !_zz_iswatched(fd) || _zz_disabled)
281        return ret;
282
283    debug("close(%i) = %i", fd, ret);
284    _zz_unregister(fd);
285
286    return ret;
287}
288
Note: See TracBrowser for help on using the repository browser.