source: zzuf/trunk/src/load-mem.c @ 1649

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