source: zzuf/trunk/src/lib-mem.c @ 1728

Last change on this file since 1728 was 1728, checked in by Sam Hocevar, 16 years ago
  • Check for <unistd.h>, too. MSVC doesn't have it.
  • Property svn:keywords set to Id
File size: 9.5 KB
Line 
1/*
2 *  zzuf - general purpose fuzzer
3 *  Copyright (c) 2006,2007 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: lib-mem.c 1728 2007-02-01 16:08:33Z 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-mem.c: loaded memory handling functions
17 */
18
19#include "config.h"
20
21/* Need this for RTLD_NEXT */
22#define _GNU_SOURCE
23/* Use this to get mmap64() on glibc systems */
24#define _LARGEFILE64_SOURCE
25/* Use this to get posix_memalign */
26#if defined HAVE_POSIX_MEMALIGN
27#   define _XOPEN_SOURCE 600
28#endif
29
30#if defined HAVE_STDINT_H
31#   include <stdint.h>
32#elif defined HAVE_INTTYPES_H
33#   include <inttypes.h>
34#endif
35#include <stdlib.h>
36#include <string.h>
37#include <errno.h>
38#include <signal.h>
39
40#if defined HAVE_MALLOC_H
41#   include <malloc.h>
42#endif
43#if defined HAVE_UNISTD_H
44#   include <unistd.h>
45#endif
46#if defined HAVE_SYS_MMAN_H
47#   include <sys/mman.h>
48#endif
49#if defined HAVE_LIBC_H
50#   include <libc.h>
51#endif
52
53#include "libzzuf.h"
54#include "lib-load.h"
55#include "debug.h"
56#include "fuzz.h"
57#include "fd.h"
58
59#if !defined SIGKILL
60#   define SIGKILL 9
61#endif
62
63/* TODO: mremap, maybe brk/sbrk (haha) */
64
65/* Library functions that we divert */
66static void *  (*ORIG(calloc))   (size_t nmemb, size_t size);
67static void *  (*ORIG(malloc))   (size_t size);
68static void    (*ORIG(free))     (void *ptr);
69#if defined HAVE_VALLOC
70static void *  (*ORIG(valloc))   (size_t size);
71#endif
72#if defined HAVE_MEMALIGN
73static void *  (*ORIG(memalign)) (size_t boundary, size_t size);
74#endif
75#if defined HAVE_POSIX_MEMALIGN
76static int     (*ORIG(posix_memalign)) (void **memptr, size_t alignment,
77                                        size_t size);
78#endif
79static void *  (*ORIG(realloc))  (void *ptr, size_t size);
80
81#if defined HAVE_MMAP
82static void *  (*ORIG(mmap))     (void *start, size_t length, int prot,
83                                  int flags, int fd, off_t offset);
84#endif
85#if defined HAVE_MMAP64
86static void *  (*ORIG(mmap64))   (void *start, size_t length, int prot,
87                                  int flags, int fd, off64_t offset);
88#endif
89#if defined HAVE_MUNMAP
90static int     (*ORIG(munmap))   (void *start, size_t length);
91#endif
92#if defined HAVE_MAP_FD
93static kern_return_t (*ORIG(map_fd)) (int fd, vm_offset_t offset,
94                                      vm_offset_t *addr, boolean_t find_space,
95                                      vm_size_t numbytes);
96#endif
97
98/* We need a static memory buffer because some functions call memory
99 * allocation routines before our library is loaded. Hell, even dlsym()
100 * calls calloc(), so we need to do something about it */
101#define DUMMY_BYTES 655360 /* 640 kB ought to be enough for anybody */
102static uint64_t dummy_buffer[DUMMY_BYTES / 8];
103static int dummy_offset = 0;
104#define DUMMY_START ((uintptr_t)dummy_buffer)
105#define DUMMY_STOP ((uintptr_t)dummy_buffer + DUMMY_BYTES)
106
107void _zz_mem_init(void)
108{
109    LOADSYM(calloc);
110    LOADSYM(malloc);
111    LOADSYM(realloc);
112}
113
114void *NEW(calloc)(size_t nmemb, size_t size)
115{
116    void *ret;
117    if(!ORIG(calloc))
118    {
119        ret = dummy_buffer + dummy_offset;
120        memset(ret, 0, (nmemb * size + 7) / 8);
121        dummy_offset += (nmemb * size + 7) / 8;
122        debug("%s(%li, %li) = %p", __func__,
123              (long int)nmemb, (long int)size, ret);
124        return ret;
125    }
126    ret = ORIG(calloc)(nmemb, size);
127    if(ret == NULL && _zz_memory && errno == ENOMEM)
128        raise(SIGKILL);
129    return ret;
130}
131
132void *NEW(malloc)(size_t size)
133{
134    void *ret;
135    if(!ORIG(malloc))
136    {
137        ret = dummy_buffer + dummy_offset;
138        dummy_offset += (size + 7) / 8;
139        debug("%s(%li) = %p", __func__, (long int)size, ret);
140        return ret;
141    }
142    ret = ORIG(malloc)(size);
143    if(ret == NULL && _zz_memory && errno == ENOMEM)
144        raise(SIGKILL);
145    return ret;
146}
147
148void NEW(free)(void *ptr)
149{
150    if((uintptr_t)ptr >= DUMMY_START && (uintptr_t)ptr < DUMMY_STOP)
151    {
152        debug("%s(%p)", __func__, ptr);
153        return;
154    }
155    LOADSYM(free);
156    ORIG(free)(ptr);
157}
158
159void *NEW(realloc)(void *ptr, size_t size)
160{
161    void *ret;
162    if(!ORIG(realloc)
163        || ((uintptr_t)ptr >= DUMMY_START && (uintptr_t)ptr < DUMMY_STOP))
164    {
165        ret = dummy_buffer + dummy_offset;
166        memcpy(ret, ptr, size);
167        dummy_offset += (size + 7) * 8;
168        debug("%s(%p, %li) = %p", __func__, ptr, (long int)size, ret);
169        return ret;
170    }
171    LOADSYM(realloc);
172    ret = ORIG(realloc)(ptr, size);
173    if(ret == NULL && _zz_memory && errno == ENOMEM)
174        raise(SIGKILL);
175    return ret;
176}
177
178#if defined HAVE_VALLOC
179void *NEW(valloc)(size_t size)
180{
181    void *ret;
182    LOADSYM(valloc);
183    ret = ORIG(valloc)(size);
184    if(ret == NULL && _zz_memory && errno == ENOMEM)
185        raise(SIGKILL);
186    return ret;
187}
188#endif
189
190#if defined HAVE_MEMALIGN
191void *NEW(memalign)(size_t boundary, size_t size)
192{
193    void *ret;
194    LOADSYM(memalign);
195    ret = ORIG(memalign)(boundary, size);
196    if(ret == NULL && _zz_memory && errno == ENOMEM)
197        raise(SIGKILL);
198    return ret;
199}
200#endif
201
202#if defined HAVE_POSIX_MEMALIGN
203int NEW(posix_memalign)(void **memptr, size_t alignment, size_t size)
204{
205    int ret;
206    LOADSYM(posix_memalign);
207    ret = ORIG(posix_memalign)(memptr, alignment, size);
208    if(ret == ENOMEM && _zz_memory)
209        raise(SIGKILL);
210    return ret;
211}
212#endif
213
214/* Table used for mmap() and munmap() */
215void **maps = NULL;
216int nbmaps = 0;
217
218#define MMAP(fn, off_t) \
219    do { \
220        LOADSYM(fn); \
221        ret = ORIG(fn)(start, length, prot, flags, fd, offset); \
222        if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd)) \
223            return ret; \
224        if(ret && length) \
225        { \
226            char *b = malloc(length); \
227            int i, oldpos; \
228            for(i = 0; i < nbmaps; i += 2) \
229                if(maps[i] == NULL) \
230                    break; \
231            if(i == nbmaps) \
232            { \
233                nbmaps += 2; \
234                maps = realloc(maps, nbmaps * sizeof(void *)); \
235            } \
236            maps[i] = b; \
237            maps[i + 1] = ret; \
238            oldpos = _zz_getpos(fd); \
239            _zz_setpos(fd, offset); /* mmap() maps the fd at offset 0 */ \
240            memcpy(b, ret, length); /* FIXME: get rid of this */ \
241            _zz_fuzz(fd, (uint8_t *)b, length); \
242            _zz_setpos(fd, oldpos); \
243            ret = b; \
244            if(length >= 4) \
245                debug("%s(%p, %li, %i, %i, %i, %lli) = %p \"%c%c%c%c...", \
246                      __func__, start, (long int)length, prot, flags, fd, \
247                      (long long int)offset, ret, b[0], b[1], b[2], b[3]); \
248            else \
249                debug("%s(%p, %li, %i, %i, %i, %lli) = %p \"%c...", \
250                      __func__, start, (long int)length, prot, flags, fd, \
251                      (long long int)offset, ret, b[0]); \
252        } \
253        else \
254            debug("%s(%p, %li, %i, %i, %i, %lli) = %p", \
255                  __func__, start, (long int)length, prot, flags, fd, \
256                  (long long int)offset, ret); \
257    } while(0)
258
259#if defined HAVE_MMAP
260void *NEW(mmap)(void *start, size_t length, int prot, int flags,
261                int fd, off_t offset)
262{
263    void *ret; MMAP(mmap, off_t); return ret;
264}
265#endif
266
267#if defined HAVE_MMAP64
268void *NEW(mmap64)(void *start, size_t length, int prot, int flags,
269                  int fd, off64_t offset)
270{
271    void *ret; MMAP(mmap64, off64_t); return ret;
272}
273#endif
274
275#if defined HAVE_MUNMAP
276int NEW(munmap)(void *start, size_t length)
277{
278    int ret, i;
279
280    LOADSYM(munmap);
281    for(i = 0; i < nbmaps; i++)
282    {
283        if(maps[i] != start)
284            continue;
285
286        free(start);
287        ret = ORIG(munmap)(maps[i + 1], length);
288        maps[i] = NULL;
289        maps[i + 1] = NULL;
290        debug("%s(%p, %li) = %i", __func__, start, (long int)length, ret);
291        return ret;
292    }
293
294    return ORIG(munmap)(start, length);
295}
296#endif
297
298#if defined HAVE_MAP_FD
299kern_return_t NEW(map_fd)(int fd, vm_offset_t offset, vm_offset_t *addr,
300                          boolean_t find_space, vm_size_t numbytes)
301{
302    kern_return_t ret;
303
304    LOADSYM(map_fd);
305    ret = ORIG(map_fd)(fd, offset, addr, find_space, numbytes);
306    if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd))
307        return ret;
308
309    if(ret == 0 && numbytes)
310    {
311        /* FIXME: do we also have to rewind the filedescriptor like in mmap? */
312        char *b = malloc(numbytes);
313        memcpy(b, (void *)*addr, numbytes);
314        _zz_fuzz(fd, (void *)b, numbytes);
315        *addr = (vm_offset_t)b;
316        /* FIXME: the map is never freed; there is no such thing as unmap_fd,
317         * but I suppose that kind of map should go when the filedescriptor is
318         * closed (unlike mmap, which returns a persistent buffer). */
319
320        if(numbytes >= 4)
321           debug("%s(%i, %lli, &%p, %i, %lli) = %i \"%c%c%c%c", __func__,
322                 fd, (long long int)offset, (void *)*addr, (int)find_space,
323                 (long long int)numbytes, ret, b[0], b[1], b[2], b[3]);
324        else
325           debug("%s(%i, %lli, &%p, %i, %lli) = %i \"%c", __func__, fd,
326                 (long long int)offset, (void *)*addr, (int)find_space,
327                 (long long int)numbytes, ret, b[0]);
328    }
329    else
330        debug("%s(%i, %lli, &%p, %i, %lli) = %i", __func__, fd,
331              (long long int)offset, (void *)*addr, (int)find_space,
332              (long long int)numbytes, ret);
333
334    return ret;
335}
336#endif
337
Note: See TracBrowser for help on using the repository browser.