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

Last change on this file since 3632 was 3632, checked in by Sam Hocevar, 11 years ago

lib-mem.c: undefine various feature macros before redefining them.

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