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

Last change on this file since 1631 was 1631, checked in by Sam Hocevar, 14 years ago
  • Implement map_fd for OS X.
  • Property svn:keywords set to Id
File size: 9.0 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 1631 2007-01-09 10:02:57Z 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    debug("read(%i, %p, %li) = %i", fd, buf, (long int)count, ret);
203    if(ret > 0)
204    {
205        _zz_fuzz(fd, buf, ret);
206        _zz_addpos(fd, ret);
207    }
208
209    /* Sanity check, can be OK though (for instance with a character device) */
210#ifdef HAVE_LSEEK64
211    if(lseek64_orig(fd, 0, SEEK_CUR) != _zz_getpos(fd))
212#else
213    if(lseek_orig(fd, 0, SEEK_CUR) != _zz_getpos(fd))
214#endif
215        debug("warning: offset inconsistency");
216
217    return ret;
218}
219
220#define LSEEK(fn, off_t) \
221    do \
222    { \
223        if(!_zz_ready) \
224            LOADSYM(fn); \
225        ret = ORIG(fn)(fd, offset, whence); \
226        if(!_zz_ready || !_zz_iswatched(fd) || _zz_disabled) \
227            return ret; \
228        debug(STR(fn)"(%i, %lli, %i) = %lli", \
229              fd, (long long int)offset, whence, (long long int)ret); \
230        if(ret != (off_t)-1) \
231            _zz_setpos(fd, ret); \
232    } while(0)
233
234off_t lseek(int fd, off_t offset, int whence)
235{
236    off_t ret;
237    LSEEK(lseek, off_t);
238    return ret;
239}
240
241#ifdef HAVE_LSEEK64
242off64_t lseek64(int fd, off64_t offset, int whence)
243{
244    off64_t ret;
245    LSEEK(lseek64, off64_t);
246    return ret;
247}
248#endif
249
250/* Used for mmap() and munmap() */
251void **maps = NULL;
252int nbmaps = 0;
253
254#define MMAP(fn, off_t) \
255    do { \
256        if(!_zz_ready) \
257            LOADSYM(fn); \
258        ret = ORIG(fn)(start, length, prot, flags, fd, offset); \
259        if(!_zz_ready || !_zz_iswatched(fd) || _zz_disabled) \
260            return ret; \
261        if(ret) \
262        { \
263            void *tmp = malloc(length); \
264            int i; \
265            for(i = 0; i < nbmaps; i += 2) \
266                if(maps[i] == NULL) \
267                    break; \
268            if(i == nbmaps) \
269            { \
270                nbmaps += 2; \
271                maps = realloc(maps, nbmaps * sizeof(void *)); \
272            } \
273            maps[i] = tmp; \
274            maps[i + 1] = ret; \
275            memcpy(tmp, ret, length); /* FIXME: get rid of this */ \
276            _zz_fuzz(fd, tmp, length); \
277            ret = tmp; \
278        } \
279        debug(STR(fn)"(%p, %li, %i, %i, %i, %lli) = %p", start, \
280              (long int)length, prot, flags, fd, (long long int)offset, ret); \
281    } while(0)
282
283void *mmap(void *start, size_t length, int prot, int flags,
284           int fd, off_t offset)
285{
286    void *ret; MMAP(mmap, off_t); return ret;
287}
288
289#ifdef HAVE_MMAP64
290void *mmap64(void *start, size_t length, int prot, int flags,
291             int fd, off64_t offset)
292{
293    void *ret; MMAP(mmap64, off64_t); return ret;
294}
295#endif
296
297int munmap(void *start, size_t length)
298{
299    int ret, i;
300
301    if(!_zz_ready)
302        LOADSYM(munmap);
303    for(i = 0; i < nbmaps; i++)
304    {
305        if(maps[i] != start)
306            continue;
307
308        free(start);
309        ret = munmap_orig(maps[i + 1], length);
310        maps[i] = NULL;
311        maps[i + 1] = NULL;
312        debug("munmap(%p, %li) = %i", start, (long int)length, ret);
313        return ret;
314    }
315
316    return munmap_orig(start, length);
317}
318
319#ifdef HAVE_MAP_FD
320kern_return_t map_fd(int fd, vm_offset_t offset, vm_offset_t *addr,
321                     boolean_t find_space, vm_size_t numbytes)
322{
323    kern_return_t ret;
324
325    if(!_zz_ready)
326        LOADSYM(map_fd);
327    ret = map_fd_orig(fd, offset, addr, find_space, numbytes);
328    if(!_zz_ready || !_zz_iswatched(fd) || _zz_disabled)
329        return ret;
330
331    if(ret == 0)
332    {
333        void *tmp = malloc(numbytes);
334        memcpy(tmp, (void *)*addr, numbytes);
335        _zz_fuzz(fd, tmp, numbytes);
336        *addr = (vm_offset_t)tmp;
337        /* FIXME: the map is never freed; there is no such thing as unmap_fd,
338         * but I suppose that kind of map should go when the filedesciptor is
339         * closed (unlike mmap, which returns a persistent buffer). */
340    }
341
342    debug("map_fd(%i, %lli, &%p, %i, %lli) = %i", fd, (long long int)offset,
343          (void *)*addr, (int)find_space, (long long int)numbytes, ret);
344
345    return ret;
346}
347#endif
348
349int close(int fd)
350{
351    int ret;
352
353    if(!_zz_ready)
354        LOADSYM(close);
355
356    /* Hey, it’s our debug channel! Silently pretend we closed it. */
357    if(fd == DEBUG_FILENO)
358        return 0;
359
360    ret = close_orig(fd);
361    if(!_zz_ready || !_zz_iswatched(fd) || _zz_disabled)
362        return ret;
363
364    debug("close(%i) = %i", fd, ret);
365    _zz_unregister(fd);
366
367    return ret;
368}
369
Note: See TracBrowser for help on using the repository browser.