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

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

Fix copyright information and remove Id tag everywhere.

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