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

Last change on this file since 2355 was 2355, checked in by sam, 6 years ago
  • Fix a crash in the realloc() wrapper occurring when dlsym() or dlopen() call realloc() with a NULL pointer.
  • Property svn:keywords set to Id
File size: 10.3 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$
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        /* XXX: If ptr is NULL, we don't copy anything. If it is non-NULL, we
177         * copy everything even if it is too big, we don't have anything to
178         * overflow really. */
179        if(ptr)
180            memcpy(ret, ptr, size);
181        dummy_offset += (size + 7) * 8;
182        debug("%s(%p, %li) = %p", __func__, ptr, (long int)size, ret);
183        return ret;
184    }
185    LOADSYM(realloc);
186    ret = ORIG(realloc)(ptr, size);
187    if(ret == NULL && _zz_memory && errno == ENOMEM)
188        raise(SIGKILL);
189    return ret;
190}
191
192#if defined HAVE_VALLOC
193void *NEW(valloc)(size_t size)
194{
195    void *ret;
196    LOADSYM(valloc);
197    ret = ORIG(valloc)(size);
198    if(ret == NULL && _zz_memory && errno == ENOMEM)
199        raise(SIGKILL);
200    return ret;
201}
202#endif
203
204#if defined HAVE_MEMALIGN
205void *NEW(memalign)(size_t boundary, size_t size)
206{
207    void *ret;
208    LOADSYM(memalign);
209    ret = ORIG(memalign)(boundary, size);
210    if(ret == NULL && _zz_memory && errno == ENOMEM)
211        raise(SIGKILL);
212    return ret;
213}
214#endif
215
216#if defined HAVE_POSIX_MEMALIGN
217int NEW(posix_memalign)(void **memptr, size_t alignment, size_t size)
218{
219    int ret;
220    LOADSYM(posix_memalign);
221    ret = ORIG(posix_memalign)(memptr, alignment, size);
222    if(ret == ENOMEM && _zz_memory)
223        raise(SIGKILL);
224    return ret;
225}
226#endif
227
228/* Table used for mmap() and munmap() */
229void **maps = NULL;
230int nbmaps = 0;
231
232#define MMAP(fn, off_t) \
233    do { \
234        char *b = MAP_FAILED; \
235        LOADSYM(fn); \
236        if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd) \
237             || !_zz_isactive(fd)) \
238            return ORIG(fn)(start, length, prot, flags, fd, offset); \
239        ret = ORIG(fn)(NULL, length, prot, flags, fd, offset); \
240        if(ret != MAP_FAILED && length) \
241        { \
242            b = ORIG(fn)(start, length, PROT_READ | PROT_WRITE, \
243                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); \
244            if(b == MAP_FAILED) \
245            { \
246                munmap(ret, length); \
247                ret = MAP_FAILED; \
248            } \
249        } \
250        if(b != MAP_FAILED) \
251        { \
252            int i, oldpos; \
253            for(i = 0; i < nbmaps; i += 2) \
254                if(maps[i] == NULL) \
255                    break; \
256            if(i == nbmaps) \
257            { \
258                nbmaps += 2; \
259                maps = realloc(maps, nbmaps * sizeof(void *)); \
260            } \
261            maps[i] = b; \
262            maps[i + 1] = ret; \
263            oldpos = _zz_getpos(fd); \
264            _zz_setpos(fd, offset); /* mmap() maps the fd at offset 0 */ \
265            memcpy(b, ret, length); /* FIXME: get rid of this */ \
266            _zz_fuzz(fd, (uint8_t *)b, length); \
267            _zz_setpos(fd, oldpos); \
268            ret = b; \
269            if(length >= 4) \
270                debug("%s(%p, %li, %i, %i, %i, %lli) = %p \"%c%c%c%c...", \
271                      __func__, start, (long int)length, prot, flags, fd, \
272                      (long long int)offset, ret, b[0], b[1], b[2], b[3]); \
273            else \
274                debug("%s(%p, %li, %i, %i, %i, %lli) = %p \"%c...", \
275                      __func__, start, (long int)length, prot, flags, fd, \
276                      (long long int)offset, ret, b[0]); \
277        } \
278        else \
279            debug("%s(%p, %li, %i, %i, %i, %lli) = %p", \
280                  __func__, start, (long int)length, prot, flags, fd, \
281                  (long long int)offset, ret); \
282    } while(0)
283
284#if defined HAVE_MMAP
285void *NEW(mmap)(void *start, size_t length, int prot, int flags,
286                int fd, off_t offset)
287{
288    void *ret; MMAP(mmap, off_t); return ret;
289}
290#endif
291
292#if defined HAVE_MMAP64
293void *NEW(mmap64)(void *start, size_t length, int prot, int flags,
294                  int fd, off64_t offset)
295{
296    void *ret; MMAP(mmap64, off64_t); return ret;
297}
298#endif
299
300#if defined HAVE_MUNMAP
301int NEW(munmap)(void *start, size_t length)
302{
303    int ret, i;
304
305    LOADSYM(munmap);
306    for(i = 0; i < nbmaps; i++)
307    {
308        if(maps[i] != start)
309            continue;
310
311        ORIG(munmap)(start, length);
312        ret = ORIG(munmap)(maps[i + 1], length);
313        maps[i] = NULL;
314        maps[i + 1] = NULL;
315        debug("%s(%p, %li) = %i", __func__, start, (long int)length, ret);
316        return ret;
317    }
318
319    return ORIG(munmap)(start, length);
320}
321#endif
322
323#if defined HAVE_MAP_FD
324kern_return_t NEW(map_fd)(int fd, vm_offset_t offset, vm_offset_t *addr,
325                          boolean_t find_space, vm_size_t numbytes)
326{
327    kern_return_t ret;
328
329    LOADSYM(map_fd);
330    ret = ORIG(map_fd)(fd, offset, addr, find_space, numbytes);
331    if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd)
332         || !_zz_isactive(fd))
333        return ret;
334
335    if(ret == 0 && numbytes)
336    {
337        /* FIXME: do we also have to rewind the filedescriptor like in mmap? */
338        char *b = malloc(numbytes);
339        memcpy(b, (void *)*addr, numbytes);
340        _zz_fuzz(fd, (void *)b, numbytes);
341        *addr = (vm_offset_t)b;
342        /* FIXME: the map is never freed; there is no such thing as unmap_fd,
343         * but I suppose that kind of map should go when the filedescriptor is
344         * closed (unlike mmap, which returns a persistent buffer). */
345
346        if(numbytes >= 4)
347           debug("%s(%i, %lli, &%p, %i, %lli) = %i \"%c%c%c%c", __func__,
348                 fd, (long long int)offset, (void *)*addr, (int)find_space,
349                 (long long int)numbytes, ret, b[0], b[1], b[2], b[3]);
350        else
351           debug("%s(%i, %lli, &%p, %i, %lli) = %i \"%c", __func__, fd,
352                 (long long int)offset, (void *)*addr, (int)find_space,
353                 (long long int)numbytes, ret, b[0]);
354    }
355    else
356        debug("%s(%i, %lli, &%p, %i, %lli) = %i", __func__, fd,
357              (long long int)offset, (void *)*addr, (int)find_space,
358              (long long int)numbytes, ret);
359
360    return ret;
361}
362#endif
363
Note: See TracBrowser for help on using the repository browser.