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

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