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

Last change on this file since 4238 was 4238, checked in by sam, 5 years ago

Fix compilation warning due to kfreebsd’s fcntl.h defining FREAD.

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