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

Last change on this file since 2354 was 2354, checked in by Sam Hocevar, 12 years ago
  • Do not try to free() on buffers that have been allocated with the real malloc, or we may crash unexpectedly, for instance if dlsym("free") calls malloc() then free() while free hasn't been loaded yet.
  • Property svn:keywords set to Id
File size: 10.1 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 2354 2008-06-10 16:21:17Z 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#if !defined MAP_ANONYMOUS
64#   define MAP_ANONYMOUS MAP_ANON
65#endif
66
67/* TODO: mremap, maybe brk/sbrk (haha) */
68
69/* Library functions that we divert */
70static void *  (*ORIG(calloc))   (size_t nmemb, size_t size);
71static void *  (*ORIG(malloc))   (size_t size);
72static void    (*ORIG(free))     (void *ptr);
73#if defined HAVE_VALLOC
74static void *  (*ORIG(valloc))   (size_t size);
75#endif
76#if defined HAVE_MEMALIGN
77static void *  (*ORIG(memalign)) (size_t boundary, size_t size);
78#endif
79#if defined HAVE_POSIX_MEMALIGN
80static int     (*ORIG(posix_memalign)) (void **memptr, size_t alignment,
81                                        size_t size);
82#endif
83static void *  (*ORIG(realloc))  (void *ptr, size_t size);
84
85#if defined HAVE_MMAP
86static void *  (*ORIG(mmap))     (void *start, size_t length, int prot,
87                                  int flags, int fd, off_t offset);
88#endif
89#if defined HAVE_MMAP64
90static void *  (*ORIG(mmap64))   (void *start, size_t length, int prot,
91                                  int flags, int fd, off64_t offset);
92#endif
93#if defined HAVE_MUNMAP
94static int     (*ORIG(munmap))   (void *start, size_t length);
95#endif
96#if defined HAVE_MAP_FD
97static kern_return_t (*ORIG(map_fd)) (int fd, vm_offset_t offset,
98                                      vm_offset_t *addr, boolean_t find_space,
99                                      vm_size_t numbytes);
100#endif
101
102/* We need a static memory buffer because some functions call memory
103 * allocation routines before our library is loaded. Hell, even dlsym()
104 * calls calloc(), so we need to do something about it */
105#define DUMMY_BYTES 655360 /* 640 kB ought to be enough for anybody */
106static uint64_t dummy_buffer[DUMMY_BYTES / 8];
107static int64_t dummy_offset = 0;
108#define DUMMY_START ((uintptr_t)dummy_buffer)
109#define DUMMY_STOP ((uintptr_t)dummy_buffer + DUMMY_BYTES)
110
111void _zz_mem_init(void)
112{
113    LOADSYM(free);
114    LOADSYM(calloc);
115    LOADSYM(malloc);
116    LOADSYM(realloc);
117}
118
119void *NEW(calloc)(size_t nmemb, size_t size)
120{
121    void *ret;
122    if(!ORIG(calloc))
123    {
124        ret = dummy_buffer + dummy_offset;
125        memset(ret, 0, (nmemb * size + 7) / 8);
126        dummy_offset += (nmemb * size + 7) / 8;
127        debug("%s(%li, %li) = %p", __func__,
128              (long int)nmemb, (long int)size, ret);
129        return ret;
130    }
131    ret = ORIG(calloc)(nmemb, size);
132    if(ret == NULL && _zz_memory && errno == ENOMEM)
133        raise(SIGKILL);
134    return ret;
135}
136
137void *NEW(malloc)(size_t size)
138{
139    void *ret;
140    if(!ORIG(malloc))
141    {
142        ret = dummy_buffer + dummy_offset;
143        dummy_offset += (size + 7) / 8;
144        debug("%s(%li) = %p", __func__, (long int)size, ret);
145        return ret;
146    }
147    ret = ORIG(malloc)(size);
148    if(ret == NULL && _zz_memory && errno == ENOMEM)
149        raise(SIGKILL);
150    return ret;
151}
152
153void NEW(free)(void *ptr)
154{
155    if((uintptr_t)ptr >= DUMMY_START && (uintptr_t)ptr < DUMMY_STOP)
156    {
157        debug("%s(%p)", __func__, ptr);
158        return;
159    }
160    if(!ORIG(free))
161    {
162        /* FIXME: memory leak */
163        debug("%s(%p) IGNORED", __func__, ptr);
164        return;
165    }
166    ORIG(free)(ptr);
167}
168
169void *NEW(realloc)(void *ptr, size_t size)
170{
171    void *ret;
172    if(!ORIG(realloc)
173        || ((uintptr_t)ptr >= DUMMY_START && (uintptr_t)ptr < DUMMY_STOP))
174    {
175        ret = dummy_buffer + dummy_offset;
176        memcpy(ret, ptr, size);
177        dummy_offset += (size + 7) * 8;
178        debug("%s(%p, %li) = %p", __func__, ptr, (long int)size, ret);
179        return ret;
180    }
181    LOADSYM(realloc);
182    ret = ORIG(realloc)(ptr, size);
183    if(ret == NULL && _zz_memory && errno == ENOMEM)
184        raise(SIGKILL);
185    return ret;
186}
187
188#if defined HAVE_VALLOC
189void *NEW(valloc)(size_t size)
190{
191    void *ret;
192    LOADSYM(valloc);
193    ret = ORIG(valloc)(size);
194    if(ret == NULL && _zz_memory && errno == ENOMEM)
195        raise(SIGKILL);
196    return ret;
197}
198#endif
199
200#if defined HAVE_MEMALIGN
201void *NEW(memalign)(size_t boundary, size_t size)
202{
203    void *ret;
204    LOADSYM(memalign);
205    ret = ORIG(memalign)(boundary, size);
206    if(ret == NULL && _zz_memory && errno == ENOMEM)
207        raise(SIGKILL);
208    return ret;
209}
210#endif
211
212#if defined HAVE_POSIX_MEMALIGN
213int NEW(posix_memalign)(void **memptr, size_t alignment, size_t size)
214{
215    int ret;
216    LOADSYM(posix_memalign);
217    ret = ORIG(posix_memalign)(memptr, alignment, size);
218    if(ret == ENOMEM && _zz_memory)
219        raise(SIGKILL);
220    return ret;
221}
222#endif
223
224/* Table used for mmap() and munmap() */
225void **maps = NULL;
226int nbmaps = 0;
227
228#define MMAP(fn, off_t) \
229    do { \
230        char *b = MAP_FAILED; \
231        LOADSYM(fn); \
232        if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd) \
233             || !_zz_isactive(fd)) \
234            return ORIG(fn)(start, length, prot, flags, fd, offset); \
235        ret = ORIG(fn)(NULL, length, prot, flags, fd, offset); \
236        if(ret != MAP_FAILED && length) \
237        { \
238            b = ORIG(fn)(start, length, PROT_READ | PROT_WRITE, \
239                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); \
240            if(b == MAP_FAILED) \
241            { \
242                munmap(ret, length); \
243                ret = MAP_FAILED; \
244            } \
245        } \
246        if(b != MAP_FAILED) \
247        { \
248            int i, oldpos; \
249            for(i = 0; i < nbmaps; i += 2) \
250                if(maps[i] == NULL) \
251                    break; \
252            if(i == nbmaps) \
253            { \
254                nbmaps += 2; \
255                maps = realloc(maps, nbmaps * sizeof(void *)); \
256            } \
257            maps[i] = b; \
258            maps[i + 1] = ret; \
259            oldpos = _zz_getpos(fd); \
260            _zz_setpos(fd, offset); /* mmap() maps the fd at offset 0 */ \
261            memcpy(b, ret, length); /* FIXME: get rid of this */ \
262            _zz_fuzz(fd, (uint8_t *)b, length); \
263            _zz_setpos(fd, oldpos); \
264            ret = b; \
265            if(length >= 4) \
266                debug("%s(%p, %li, %i, %i, %i, %lli) = %p \"%c%c%c%c...", \
267                      __func__, start, (long int)length, prot, flags, fd, \
268                      (long long int)offset, ret, b[0], b[1], b[2], b[3]); \
269            else \
270                debug("%s(%p, %li, %i, %i, %i, %lli) = %p \"%c...", \
271                      __func__, start, (long int)length, prot, flags, fd, \
272                      (long long int)offset, ret, b[0]); \
273        } \
274        else \
275            debug("%s(%p, %li, %i, %i, %i, %lli) = %p", \
276                  __func__, start, (long int)length, prot, flags, fd, \
277                  (long long int)offset, ret); \
278    } while(0)
279
280#if defined HAVE_MMAP
281void *NEW(mmap)(void *start, size_t length, int prot, int flags,
282                int fd, off_t offset)
283{
284    void *ret; MMAP(mmap, off_t); return ret;
285}
286#endif
287
288#if defined HAVE_MMAP64
289void *NEW(mmap64)(void *start, size_t length, int prot, int flags,
290                  int fd, off64_t offset)
291{
292    void *ret; MMAP(mmap64, off64_t); return ret;
293}
294#endif
295
296#if defined HAVE_MUNMAP
297int NEW(munmap)(void *start, size_t length)
298{
299    int ret, i;
300
301    LOADSYM(munmap);
302    for(i = 0; i < nbmaps; i++)
303    {
304        if(maps[i] != start)
305            continue;
306
307        ORIG(munmap)(start, length);
308        ret = ORIG(munmap)(maps[i + 1], length);
309        maps[i] = NULL;
310        maps[i + 1] = NULL;
311        debug("%s(%p, %li) = %i", __func__, start, (long int)length, ret);
312        return ret;
313    }
314
315    return ORIG(munmap)(start, length);
316}
317#endif
318
319#if defined HAVE_MAP_FD
320kern_return_t NEW(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    LOADSYM(map_fd);
326    ret = ORIG(map_fd)(fd, offset, addr, find_space, numbytes);
327    if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd)
328         || !_zz_isactive(fd))
329        return ret;
330
331    if(ret == 0 && numbytes)
332    {
333        /* FIXME: do we also have to rewind the filedescriptor like in mmap? */
334        char *b = malloc(numbytes);
335        memcpy(b, (void *)*addr, numbytes);
336        _zz_fuzz(fd, (void *)b, numbytes);
337        *addr = (vm_offset_t)b;
338        /* FIXME: the map is never freed; there is no such thing as unmap_fd,
339         * but I suppose that kind of map should go when the filedescriptor is
340         * closed (unlike mmap, which returns a persistent buffer). */
341
342        if(numbytes >= 4)
343           debug("%s(%i, %lli, &%p, %i, %lli) = %i \"%c%c%c%c", __func__,
344                 fd, (long long int)offset, (void *)*addr, (int)find_space,
345                 (long long int)numbytes, ret, b[0], b[1], b[2], b[3]);
346        else
347           debug("%s(%i, %lli, &%p, %i, %lli) = %i \"%c", __func__, fd,
348                 (long long int)offset, (void *)*addr, (int)find_space,
349                 (long long int)numbytes, ret, b[0]);
350    }
351    else
352        debug("%s(%i, %lli, &%p, %i, %lli) = %i", __func__, fd,
353              (long long int)offset, (void *)*addr, (int)find_space,
354              (long long int)numbytes, ret);
355
356    return ret;
357}
358#endif
359
Note: See TracBrowser for help on using the repository browser.