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

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