source: zzuf/trunk/src/load-mem.c @ 1679

Last change on this file since 1679 was 1679, checked in by Sam Hocevar, 16 years ago
  • Got rid of the *_load() functions. Now each diverted function is supposed to check that the *_orig() functions it calls are properly loaded.
  • Property svn:keywords set to Id
File size: 8.6 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: load-mem.c 1679 2007-01-16 14:36:33Z 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/* Use this to get mmap64() on glibc systems */
24#define _LARGEFILE64_SOURCE
25/* Use this to get posix_memalign */
26#if defined HAVE_POSIX_MEMALIGN
27#   define _XOPEN_SOURCE 600
28#endif
29
30#if defined HAVE_STDINT_H
31#   include <stdint.h>
32#elif defined HAVE_INTTYPES_H
33#   include <inttypes.h>
34#endif
35#include <stdlib.h>
36#include <string.h>
37#include <dlfcn.h>
38#include <errno.h>
39#include <signal.h>
40
41#if defined HAVE_MALLOC_H
42#   include <malloc.h>
43#endif
44#include <unistd.h>
45#include <sys/mman.h>
46#if defined HAVE_LIBC_H
47#   include <libc.h>
48#endif
49
50#include "libzzuf.h"
51#include "debug.h"
52#include "fuzz.h"
53#include "load.h"
54#include "fd.h"
55
56/* TODO: mremap, maybe brk/sbrk (haha) */
57
58/* Library functions that we divert */
59static void *  (*calloc_orig)   (size_t nmemb, size_t size);
60static void *  (*malloc_orig)   (size_t size);
61static void    (*free_orig)     (void *ptr);
62static void *  (*valloc_orig)   (size_t size);
63#ifdef HAVE_MEMALIGN
64static void *  (*memalign_orig) (size_t boundary, size_t size);
65#endif
66#ifdef HAVE_POSIX_MEMALIGN
67static int     (*posix_memalign_orig) (void **memptr, size_t alignment,
68                                       size_t size);
69#endif
70static void *  (*realloc_orig)  (void *ptr, size_t size);
71
72static void *  (*mmap_orig)     (void *start, size_t length, int prot,
73                                 int flags, int fd, off_t offset);
74#ifdef HAVE_MMAP64
75static void *  (*mmap64_orig)   (void *start, size_t length, int prot,
76                                 int flags, int fd, off64_t offset);
77#endif
78static int     (*munmap_orig)   (void *start, size_t length);
79#ifdef HAVE_MAP_FD
80static kern_return_t (*map_fd_orig) (int fd, vm_offset_t offset,
81                                     vm_offset_t *addr, boolean_t find_space,
82                                     vm_size_t numbytes);
83#endif
84
85/* We need a static memory buffer because some functions call memory
86 * allocation routines before our library is loaded. Hell, even dlsym()
87 * calls calloc(), so we need to do something about it */
88#define DUMMY_BYTES 655360 /* 640 kB ought to be enough for anybody */
89static uint64_t dummy_buffer[DUMMY_BYTES / 8];
90static int dummy_offset = 0;
91#define DUMMY_START ((uintptr_t)dummy_buffer)
92#define DUMMY_STOP ((uintptr_t)dummy_buffer + DUMMY_BYTES)
93
94void *calloc(size_t nmemb, size_t size)
95{
96    void *ret;
97    if(!calloc_orig)
98    {
99        ret = dummy_buffer + dummy_offset;
100        memset(ret, 0, (nmemb * size + 7) / 8);
101        dummy_offset += (nmemb * size + 7) / 8;
102        return ret;
103    }
104    ret = calloc_orig(nmemb, size);
105    if(ret == NULL && _zz_memory && errno == ENOMEM)
106        raise(SIGKILL);
107    return ret;
108}
109
110void *malloc(size_t size)
111{
112    void *ret;
113    if(!malloc_orig)
114    {
115        ret = dummy_buffer + dummy_offset;
116        dummy_offset += (size + 7) / 8;
117        return ret;
118    }
119    ret = malloc_orig(size);
120    if(ret == NULL && _zz_memory && errno == ENOMEM)
121        raise(SIGKILL);
122    return ret;
123}
124
125void free(void *ptr)
126{
127    if((uintptr_t)ptr >= DUMMY_START && (uintptr_t)ptr < DUMMY_STOP)
128        return;
129    LOADSYM(free);
130    free_orig(ptr);
131}
132
133void *realloc(void *ptr, size_t size)
134{
135    void *ret;
136    if((uintptr_t)ptr >= DUMMY_START && (uintptr_t)ptr < DUMMY_STOP)
137    {
138        ret = dummy_buffer + dummy_offset;
139        memcpy(ret, ptr, size);
140        dummy_offset += (size + 7) * 8;
141        return ret;
142    }
143    LOADSYM(realloc);
144    ret = realloc_orig(ptr, size);
145    if(ret == NULL && _zz_memory && errno == ENOMEM)
146        raise(SIGKILL);
147    return ret;
148}
149
150void *valloc(size_t size)
151{
152    void *ret;
153    LOADSYM(valloc);
154    ret = valloc_orig(size);
155    if(ret == NULL && _zz_memory && errno == ENOMEM)
156        raise(SIGKILL);
157    return ret;
158}
159
160#ifdef HAVE_MEMALIGN
161void *memalign(size_t boundary, size_t size)
162{
163    void *ret;
164    LOADSYM(memalign);
165    ret = memalign_orig(boundary, size);
166    if(ret == NULL && _zz_memory && errno == ENOMEM)
167        raise(SIGKILL);
168    return ret;
169}
170#endif
171
172#ifdef HAVE_POSIX_MEMALIGN
173int posix_memalign(void **memptr, size_t alignment, size_t size)
174{
175    int ret;
176    LOADSYM(posix_memalign);
177    ret = posix_memalign_orig(memptr, alignment, size);
178    if(ret == ENOMEM && _zz_memory)
179        raise(SIGKILL);
180    return ret;
181}
182#endif
183
184/* Table used for mmap() and munmap() */
185void **maps = NULL;
186int nbmaps = 0;
187
188#define MMAP(fn, off_t) \
189    do { \
190        LOADSYM(fn); \
191        ret = ORIG(fn)(start, length, prot, flags, fd, offset); \
192        if(!_zz_ready || !_zz_iswatched(fd) || _zz_disabled) \
193            return ret; \
194        if(ret && length) \
195        { \
196            char *b = malloc(length); \
197            int i, oldpos; \
198            for(i = 0; i < nbmaps; i += 2) \
199                if(maps[i] == NULL) \
200                    break; \
201            if(i == nbmaps) \
202            { \
203                nbmaps += 2; \
204                maps = realloc(maps, nbmaps * sizeof(void *)); \
205            } \
206            maps[i] = b; \
207            maps[i + 1] = ret; \
208            oldpos = _zz_getpos(fd); \
209            _zz_setpos(fd, offset); /* mmap() maps the fd at offset 0 */ \
210            memcpy(b, ret, length); /* FIXME: get rid of this */ \
211            _zz_fuzz(fd, (uint8_t *)b, length); \
212            _zz_setpos(fd, oldpos); \
213            ret = b; \
214            if(length >= 4) \
215                debug(STR(fn)"(%p, %li, %i, %i, %i, %lli) = %p \"%c%c%c%c...", \
216                      start, (long int)length, prot, flags, fd, \
217                      (long long int)offset, ret, b[0], b[1], b[2], b[3]); \
218            else \
219                debug(STR(fn)"(%p, %li, %i, %i, %i, %lli) = %p \"%c...", \
220                      start, (long int)length, prot, flags, fd, \
221                      (long long int)offset, ret, b[0]); \
222        } \
223        else \
224            debug(STR(fn)"(%p, %li, %i, %i, %i, %lli) = %p", \
225                  start, (long int)length, prot, flags, fd, \
226                  (long long int)offset, ret); \
227    } while(0)
228
229void *mmap(void *start, size_t length, int prot, int flags,
230           int fd, off_t offset)
231{
232    void *ret; MMAP(mmap, off_t); return ret;
233}
234
235#ifdef HAVE_MMAP64
236void *mmap64(void *start, size_t length, int prot, int flags,
237             int fd, off64_t offset)
238{
239    void *ret; MMAP(mmap64, off64_t); return ret;
240}
241#endif
242
243int munmap(void *start, size_t length)
244{
245    int ret, i;
246
247    LOADSYM(munmap);
248    for(i = 0; i < nbmaps; i++)
249    {
250        if(maps[i] != start)
251            continue;
252
253        free(start);
254        ret = munmap_orig(maps[i + 1], length);
255        maps[i] = NULL;
256        maps[i + 1] = NULL;
257        debug("munmap(%p, %li) = %i", start, (long int)length, ret);
258        return ret;
259    }
260
261    return munmap_orig(start, length);
262}
263
264#ifdef HAVE_MAP_FD
265kern_return_t map_fd(int fd, vm_offset_t offset, vm_offset_t *addr,
266                     boolean_t find_space, vm_size_t numbytes)
267{
268    kern_return_t ret;
269
270    LOADSYM(map_fd);
271    ret = map_fd_orig(fd, offset, addr, find_space, numbytes);
272    if(!_zz_ready || !_zz_iswatched(fd) || _zz_disabled)
273        return ret;
274
275    if(ret == 0 && numbytes)
276    {
277        /* FIXME: do we also have to rewind the filedescriptor like in mmap? */
278        char *b = malloc(numbytes);
279        memcpy(b, (void *)*addr, numbytes);
280        _zz_fuzz(fd, (void *)b, numbytes);
281        *addr = (vm_offset_t)b;
282        /* FIXME: the map is never freed; there is no such thing as unmap_fd,
283         * but I suppose that kind of map should go when the filedescriptor is
284         * closed (unlike mmap, which returns a persistent buffer). */
285
286        if(numbytes >= 4)
287           debug("map_fd(%i, %lli, &%p, %i, %lli) = %i \"%c%c%c%c", fd,
288                 (long long int)offset, (void *)*addr, (int)find_space,
289                 (long long int)numbytes, ret, b[0], b[1], b[2], b[3]);
290        else
291           debug("map_fd(%i, %lli, &%p, %i, %lli) = %i \"%c", fd,
292                 (long long int)offset, (void *)*addr, (int)find_space,
293                 (long long int)numbytes, ret, b[0]);
294    }
295    else
296        debug("map_fd(%i, %lli, &%p, %i, %lli) = %i", fd, (long long int)offset,
297              (void *)*addr, (int)find_space, (long long int)numbytes, ret);
298
299    return ret;
300}
301#endif
302
Note: See TracBrowser for help on using the repository browser.