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

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