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

Last change on this file since 1638 was 1638, checked in by Sam Hocevar, 15 years ago
  • Fixed double mmap debug message.
  • 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 1638 2007-01-09 16:39:07Z 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        else \
301            debug(STR(fn)"(%p, %li, %i, %i, %i, %lli) = %p", \
302                  start, (long int)length, prot, flags, fd, \
303                  (long long int)offset, ret); \
304    } while(0)
305
306void *mmap(void *start, size_t length, int prot, int flags,
307           int fd, off_t offset)
308{
309    void *ret; MMAP(mmap, off_t); return ret;
310}
311
312#ifdef HAVE_MMAP64
313void *mmap64(void *start, size_t length, int prot, int flags,
314             int fd, off64_t offset)
315{
316    void *ret; MMAP(mmap64, off64_t); return ret;
317}
318#endif
319
320int munmap(void *start, size_t length)
321{
322    int ret, i;
323
324    if(!_zz_ready)
325        LOADSYM(munmap);
326    for(i = 0; i < nbmaps; i++)
327    {
328        if(maps[i] != start)
329            continue;
330
331        free(start);
332        ret = munmap_orig(maps[i + 1], length);
333        maps[i] = NULL;
334        maps[i + 1] = NULL;
335        debug("munmap(%p, %li) = %i", start, (long int)length, ret);
336        return ret;
337    }
338
339    return munmap_orig(start, length);
340}
341
342#ifdef HAVE_MAP_FD
343kern_return_t map_fd(int fd, vm_offset_t offset, vm_offset_t *addr,
344                     boolean_t find_space, vm_size_t numbytes)
345{
346    kern_return_t ret;
347
348    if(!_zz_ready)
349        LOADSYM(map_fd);
350    ret = map_fd_orig(fd, offset, addr, find_space, numbytes);
351    if(!_zz_ready || !_zz_iswatched(fd) || _zz_disabled)
352        return ret;
353
354    if(ret == 0 && numbytes)
355    {
356        /* FIXME: do we also have to rewind the filedescriptor like in mmap? */
357        void *b = malloc(numbytes);
358        memcpy(b, (void *)*addr, numbytes);
359        _zz_fuzz(fd, b, numbytes);
360        *addr = (vm_offset_t)b;
361        /* FIXME: the map is never freed; there is no such thing as unmap_fd,
362         * but I suppose that kind of map should go when the filedescriptor is
363         * closed (unlike mmap, which returns a persistent buffer). */
364
365        if(numbytes >= 4)
366           debug("map_fd(%i, %lli, &%p, %i, %lli) = %i \"%c%c%c%c", fd,
367                 (long long int)offset, (void *)*addr, (int)find_space,
368                 (long long int)numbytes, ret, b[0], b[1], b[2], b[3]);
369        else
370           debug("map_fd(%i, %lli, &%p, %i, %lli) = %i \"%c", fd,
371                 (long long int)offset, (void *)*addr, (int)find_space,
372                 (long long int)numbytes, ret, b[0]);
373    }
374    else
375        debug("map_fd(%i, %lli, &%p, %i, %lli) = %i", fd, (long long int)offset,
376              (void *)*addr, (int)find_space, (long long int)numbytes, ret);
377
378    return ret;
379}
380#endif
381
382int close(int fd)
383{
384    int ret;
385
386    if(!_zz_ready)
387        LOADSYM(close);
388
389    /* Hey, it’s our debug channel! Silently pretend we closed it. */
390    if(fd == DEBUG_FILENO)
391        return 0;
392
393    ret = close_orig(fd);
394    if(!_zz_ready || !_zz_iswatched(fd) || _zz_disabled)
395        return ret;
396
397    debug("close(%i) = %i", fd, ret);
398    _zz_unregister(fd);
399
400    return ret;
401}
402
Note: See TracBrowser for help on using the repository browser.