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

Last change on this file since 1637 was 1637, checked in by Sam Hocevar, 15 years ago
  • Add verbosity to read() and mmap() so that we roughly know where we are reading.
  • Property svn:keywords set to Id
File size: 10.5 KB
Line 
1/*
2 *  zzuf - general purpose fuzzer
3 *  Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: load-fd.c 1637 2007-01-09 16:16:00Z sam $
7 *
8 *  This program is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15/*
16 *  load-fd.c: loaded file descriptor functions
17 */
18
19#include "config.h"
20
21/* Can't remember what that's for */
22#define _GNU_SOURCE
23/* Use this to get lseek64() on glibc systems */
24#define _LARGEFILE64_SOURCE
25
26#if defined HAVE_STDINT_H
27#   include <stdint.h>
28#elif defined HAVE_INTTYPES_H
29#   include <inttypes.h>
30#endif
31#include <stdlib.h>
32#include <string.h>
33#include <dlfcn.h>
34
35#include <sys/types.h>
36#include <sys/socket.h>
37#include <sys/mman.h>
38#include <unistd.h>
39#include <fcntl.h>
40#include <stdarg.h>
41#if defined HAVE_LIBC_H
42#   include <libc.h>
43#endif
44
45#include "libzzuf.h"
46#include "debug.h"
47#include "fuzz.h"
48#include "load.h"
49#include "fd.h"
50
51#ifdef HAVE_SOCKLEN_T
52#   define SOCKLEN_T socklen_t
53#else
54#   define SOCKLEN_T int
55#endif
56
57/* Library functions that we divert */
58static int     (*open_orig)    (const char *file, int oflag, ...);
59#ifdef HAVE_OPEN64
60static int     (*open64_orig)  (const char *file, int oflag, ...);
61#endif
62static int     (*accept_orig)  (int sockfd, struct sockaddr *addr,
63                                SOCKLEN_T *addrlen);
64static int     (*socket_orig)  (int domain, int type, int protocol);
65static ssize_t (*read_orig)    (int fd, void *buf, size_t count);
66static off_t   (*lseek_orig)   (int fd, off_t offset, int whence);
67#ifdef HAVE_LSEEK64
68static off64_t (*lseek64_orig) (int fd, off64_t offset, int whence);
69#endif
70static void *  (*mmap_orig)    (void *start, size_t length, int prot,
71                                int flags, int fd, off_t offset);
72#ifdef HAVE_LSEEK64
73static void *  (*mmap64_orig)  (void *start, size_t length, int prot,
74                                int flags, int fd, off64_t offset);
75#endif
76static int     (*munmap_orig)  (void *start, size_t length);
77#ifdef HAVE_MAP_FD
78static kern_return_t (*map_fd_orig) (int fd, vm_offset_t offset,
79                                     vm_offset_t *addr, boolean_t find_space,
80                                     vm_size_t numbytes);
81#endif
82static int     (*close_orig)   (int fd);
83
84
85void _zz_load_fd(void)
86{
87    LOADSYM(open);
88#ifdef HAVE_OPEN64
89    LOADSYM(open64);
90#endif
91    LOADSYM(accept);
92    LOADSYM(socket);
93    LOADSYM(read);
94    LOADSYM(lseek);
95#ifdef HAVE_LSEEK64
96    LOADSYM(lseek64);
97#endif
98    LOADSYM(mmap);
99#ifdef HAVE_MMAP64
100    LOADSYM(mmap64);
101#endif
102    LOADSYM(munmap);
103#ifdef HAVE_MAP_FD
104    LOADSYM(map_fd);
105#endif
106    LOADSYM(close);
107}
108
109#define OPEN(fn) \
110    do \
111    { \
112        int mode = 0; \
113        if(!_zz_ready) \
114            LOADSYM(fn); \
115        if(oflag & O_CREAT) \
116        { \
117            va_list va; \
118            va_start(va, oflag); \
119            mode = va_arg(va, int); \
120            va_end(va); \
121            ret = ORIG(fn)(file, oflag, mode); \
122        } \
123        else \
124        { \
125            ret = ORIG(fn)(file, oflag); \
126        } \
127        if(!_zz_ready || _zz_disabled) \
128            return ret; \
129        if(ret >= 0 \
130            && ((oflag & (O_RDONLY | O_RDWR | O_WRONLY)) != O_WRONLY) \
131            && _zz_mustwatch(file)) \
132        { \
133            if(oflag & O_CREAT) \
134                debug(STR(fn) "(\"%s\", %i, %i) = %i", \
135                      file, oflag, mode, ret); \
136            else \
137                debug(STR(fn) "(\"%s\", %i) = %i", file, oflag, ret); \
138            _zz_register(ret); \
139        } \
140    } while(0)
141
142int open(const char *file, int oflag, ...)
143{
144    int ret; OPEN(open); return ret;
145}
146
147#ifdef HAVE_OPEN64
148int open64(const char *file, int oflag, ...)
149{
150    int ret; OPEN(open64); return ret;
151}
152#endif
153
154int accept(int sockfd, struct sockaddr *addr, SOCKLEN_T *addrlen)
155{
156    int ret;
157
158    if(!_zz_ready)
159        LOADSYM(accept);
160    ret = accept_orig(sockfd, addr, addrlen);
161    if(!_zz_ready || _zz_disabled || !_zz_network)
162        return ret;
163
164    if(ret >= 0)
165    {
166        debug("accept(%i, %p, %p) = %i", sockfd, addr, addrlen, ret);
167        _zz_register(ret);
168    }
169
170    return ret;
171}
172
173int socket(int domain, int type, int protocol)
174{
175    int ret;
176
177    if(!_zz_ready)
178        LOADSYM(socket);
179    ret = socket_orig(domain, type, protocol);
180    if(!_zz_ready || _zz_disabled || !_zz_network)
181        return ret;
182
183    if(ret >= 0)
184    {
185        debug("socket(%i, %i, %i) = %i", domain, type, protocol, ret);
186        _zz_register(ret);
187    }
188
189    return ret;
190}
191
192ssize_t read(int fd, void *buf, size_t count)
193{
194    int ret;
195
196    if(!_zz_ready)
197        LOADSYM(read);
198    ret = read_orig(fd, buf, count);
199    if(!_zz_ready || !_zz_iswatched(fd) || _zz_disabled)
200        return ret;
201
202    if(ret > 0)
203    {
204        char *b = buf;
205
206        _zz_fuzz(fd, buf, ret);
207        _zz_addpos(fd, ret);
208
209        if(ret >= 4)
210            debug("read(%i, %p, %li) = %i \"%c%c%c%c...", fd, buf,
211                  (long int)count, ret, b[0], b[1], b[2], b[3]);
212        else
213            debug("read(%i, %p, %li) = %i \"%c...", fd, buf,
214                  (long int)count, ret, b[0]);
215    }
216    else
217        debug("read(%i, %p, %li) = %i", fd, buf, (long int)count, ret);
218
219    /* Sanity check, can be OK though (for instance with a character device) */
220#ifdef HAVE_LSEEK64
221    if(lseek64_orig(fd, 0, SEEK_CUR) != _zz_getpos(fd))
222#else
223    if(lseek_orig(fd, 0, SEEK_CUR) != _zz_getpos(fd))
224#endif
225        debug("warning: offset inconsistency");
226
227    return ret;
228}
229
230#define LSEEK(fn, off_t) \
231    do \
232    { \
233        if(!_zz_ready) \
234            LOADSYM(fn); \
235        ret = ORIG(fn)(fd, offset, whence); \
236        if(!_zz_ready || !_zz_iswatched(fd) || _zz_disabled) \
237            return ret; \
238        debug(STR(fn)"(%i, %lli, %i) = %lli", \
239              fd, (long long int)offset, whence, (long long int)ret); \
240        if(ret != (off_t)-1) \
241            _zz_setpos(fd, ret); \
242    } while(0)
243
244off_t lseek(int fd, off_t offset, int whence)
245{
246    off_t ret;
247    LSEEK(lseek, off_t);
248    return ret;
249}
250
251#ifdef HAVE_LSEEK64
252off64_t lseek64(int fd, off64_t offset, int whence)
253{
254    off64_t ret;
255    LSEEK(lseek64, off64_t);
256    return ret;
257}
258#endif
259
260/* Used for mmap() and munmap() */
261void **maps = NULL;
262int nbmaps = 0;
263
264#define MMAP(fn, off_t) \
265    do { \
266        if(!_zz_ready) \
267            LOADSYM(fn); \
268        ret = ORIG(fn)(start, length, prot, flags, fd, offset); \
269        if(!_zz_ready || !_zz_iswatched(fd) || _zz_disabled) \
270            return ret; \
271        if(ret && length) \
272        { \
273            char *b = malloc(length); \
274            int i, oldpos; \
275            for(i = 0; i < nbmaps; i += 2) \
276                if(maps[i] == NULL) \
277                    break; \
278            if(i == nbmaps) \
279            { \
280                nbmaps += 2; \
281                maps = realloc(maps, nbmaps * sizeof(void *)); \
282            } \
283            maps[i] = b; \
284            maps[i + 1] = ret; \
285            oldpos = _zz_getpos(fd); \
286            _zz_setpos(fd, offset); /* mmap() maps the fd at offset 0 */ \
287            memcpy(b, ret, length); /* FIXME: get rid of this */ \
288            _zz_fuzz(fd, (uint8_t *)b, length); \
289            _zz_setpos(fd, oldpos); \
290            ret = b; \
291            if(length >= 4) \
292                debug(STR(fn)"(%p, %li, %i, %i, %i, %lli) = %p \"%c%c%c%c...", \
293                      start, (long int)length, prot, flags, fd, \
294                      (long long int)offset, ret, b[0], b[1], b[2], b[3]); \
295            else \
296                debug(STR(fn)"(%p, %li, %i, %i, %i, %lli) = %p \"%c...", \
297                      start, (long int)length, prot, flags, fd, \
298                      (long long int)offset, ret, b[0]); \
299        } \
300        debug(STR(fn)"(%p, %li, %i, %i, %i, %lli) = %p", start, \
301              (long int)length, prot, flags, fd, (long long int)offset, ret); \
302    } while(0)
303
304void *mmap(void *start, size_t length, int prot, int flags,
305           int fd, off_t offset)
306{
307    void *ret; MMAP(mmap, off_t); return ret;
308}
309
310#ifdef HAVE_MMAP64
311void *mmap64(void *start, size_t length, int prot, int flags,
312             int fd, off64_t offset)
313{
314    void *ret; MMAP(mmap64, off64_t); return ret;
315}
316#endif
317
318int munmap(void *start, size_t length)
319{
320    int ret, i;
321
322    if(!_zz_ready)
323        LOADSYM(munmap);
324    for(i = 0; i < nbmaps; i++)
325    {
326        if(maps[i] != start)
327            continue;
328
329        free(start);
330        ret = munmap_orig(maps[i + 1], length);
331        maps[i] = NULL;
332        maps[i + 1] = NULL;
333        debug("munmap(%p, %li) = %i", start, (long int)length, ret);
334        return ret;
335    }
336
337    return munmap_orig(start, length);
338}
339
340#ifdef HAVE_MAP_FD
341kern_return_t map_fd(int fd, vm_offset_t offset, vm_offset_t *addr,
342                     boolean_t find_space, vm_size_t numbytes)
343{
344    kern_return_t ret;
345
346    if(!_zz_ready)
347        LOADSYM(map_fd);
348    ret = map_fd_orig(fd, offset, addr, find_space, numbytes);
349    if(!_zz_ready || !_zz_iswatched(fd) || _zz_disabled)
350        return ret;
351
352    if(ret == 0 && numbytes)
353    {
354        /* FIXME: do we also have to rewind the filedescriptor like in mmap? */
355        void *b = malloc(numbytes);
356        memcpy(b, (void *)*addr, numbytes);
357        _zz_fuzz(fd, b, numbytes);
358        *addr = (vm_offset_t)b;
359        /* FIXME: the map is never freed; there is no such thing as unmap_fd,
360         * but I suppose that kind of map should go when the filedescriptor is
361         * closed (unlike mmap, which returns a persistent buffer). */
362
363        if(numbytes >= 4)
364           debug("map_fd(%i, %lli, &%p, %i, %lli) = %i \"%c%c%c%c", fd,
365                 (long long int)offset, (void *)*addr, (int)find_space,
366                 (long long int)numbytes, ret, b[0], b[1], b[2], b[3]);
367        else
368           debug("map_fd(%i, %lli, &%p, %i, %lli) = %i \"%c", fd,
369                 (long long int)offset, (void *)*addr, (int)find_space,
370                 (long long int)numbytes, ret, b[0]);
371    }
372    else
373        debug("map_fd(%i, %lli, &%p, %i, %lli) = %i", fd, (long long int)offset,
374              (void *)*addr, (int)find_space, (long long int)numbytes, ret);
375
376    return ret;
377}
378#endif
379
380int close(int fd)
381{
382    int ret;
383
384    if(!_zz_ready)
385        LOADSYM(close);
386
387    /* Hey, it’s our debug channel! Silently pretend we closed it. */
388    if(fd == DEBUG_FILENO)
389        return 0;
390
391    ret = close_orig(fd);
392    if(!_zz_ready || !_zz_iswatched(fd) || _zz_disabled)
393        return ret;
394
395    debug("close(%i) = %i", fd, ret);
396    _zz_unregister(fd);
397
398    return ret;
399}
400
Note: See TracBrowser for help on using the repository browser.