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

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

Fix compilation warnings and errors on OpenSolaris? caused by a few of
our source feature macros.

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