source: zzuf/trunk/src/load-stream.c @ 1588

Revision 1588, 11.1 KB checked in by sam, 6 years ago (diff)
  • Fix for BSD machines: getc() may be defined as a macro.
  • Property svn:keywords set to Id
Line 
1/*
2 *  zzuf - general purpose fuzzer
3 *  Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
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-stream.c: loaded stream functions
17 */
18
19#include "config.h"
20
21#define _GNU_SOURCE /* for getline() and getdelim() */
22
23#if defined HAVE_STDINT_H
24#   include <stdint.h>
25#elif defined HAVE_INTTYPES_H
26#   include <inttypes.h>
27#endif
28#include <stdlib.h>
29#include <dlfcn.h>
30
31#include <stdio.h>
32
33#include "libzzuf.h"
34#include "debug.h"
35#include "fuzz.h"
36#include "load.h"
37
38/* Library functions that we divert */
39static FILE *  (*fopen_orig)   (const char *path, const char *mode);
40#ifdef HAVE_FOPEN64
41static FILE *  (*fopen64_orig) (const char *path, const char *mode);
42#endif
43static int     (*fseek_orig)   (FILE *stream, long offset, int whence);
44static void    (*rewind_orig)  (FILE *stream);
45static size_t  (*fread_orig)   (void *ptr, size_t size, size_t nmemb,
46                                FILE *stream);
47static int     (*getc_orig)    (FILE *stream);
48static int     (*fgetc_orig)   (FILE *stream);
49static char *  (*fgets_orig)   (char *s, int size, FILE *stream);
50static int     (*ungetc_orig)  (int c, FILE *stream);
51static int     (*fclose_orig)  (FILE *fp);
52
53/* Additional GNUisms */
54#ifdef HAVE_GETLINE
55static ssize_t (*getline_orig)    (char **lineptr, size_t *n, FILE *stream);
56#endif
57#ifdef HAVE_GETDELIM
58static ssize_t (*getdelim_orig)   (char **lineptr, size_t *n, int delim,
59                                   FILE *stream);
60#endif
61#ifdef HAVE___GETDELIM
62static ssize_t (*__getdelim_orig) (char **lineptr, size_t *n, int delim,
63                                   FILE *stream);
64#endif
65
66/* Additional BSDisms */
67#ifdef HAVE_FGETLN
68static char *  (*fgetln_orig) (FILE *stream, size_t *len);
69#endif
70
71void _zz_load_stream(void)
72{
73    LOADSYM(fopen);
74#ifdef HAVE_FOPEN64
75    LOADSYM(fopen64);
76#endif
77    LOADSYM(fseek);
78    LOADSYM(rewind);
79    LOADSYM(fread);
80    LOADSYM(getc);
81    LOADSYM(fgetc);
82    LOADSYM(fgets);
83    LOADSYM(ungetc);
84    LOADSYM(fclose);
85#ifdef HAVE_GETLINE
86    LOADSYM(getline);
87#endif
88#ifdef HAVE_GETDELIM
89    LOADSYM(getdelim);
90#endif
91#ifdef HAVE___GETDELIM
92    LOADSYM(__getdelim);
93#endif
94#ifdef HAVE_FGETLN
95    LOADSYM(fgetln);
96#endif
97}
98
99/* Our function wrappers */
100#define FOPEN(fn) \
101    do \
102    { \
103        if(!_zz_ready) \
104        { \
105            LOADSYM(fn); \
106            return ORIG(fn)(path, mode); \
107        } \
108        _zz_disabled = 1; \
109        ret = ORIG(fn)(path, mode); \
110        _zz_disabled = 0; \
111        if(ret && _zz_mustwatch(path)) \
112        { \
113            int fd = fileno(ret); \
114            _zz_register(fd); \
115            debug(STR(fn) "(\"%s\", \"%s\") = [%i]", path, mode, fd); \
116        } \
117    } while(0)
118
119FILE *fopen(const char *path, const char *mode)
120{
121    FILE *ret; FOPEN(fopen); return ret;
122}
123
124#ifdef HAVE_FOPEN64
125FILE *fopen64(const char *path, const char *mode)
126{
127    FILE *ret; FOPEN(fopen64); return ret;
128}
129#endif
130
131int fseek(FILE *stream, long offset, int whence)
132{
133    int ret, fd;
134
135    if(!_zz_ready)
136        LOADSYM(fseek);
137    fd = fileno(stream);
138    if(!_zz_ready || !_zz_iswatched(fd))
139        return fseek_orig(stream, offset, whence);
140
141    _zz_disabled = 1;
142    ret = fseek_orig(stream, offset, whence);
143    _zz_disabled = 0;
144    debug("fseek([%i], %li, %i) = %i", fd, offset, whence, ret);
145    if(ret != 0)
146        return ret;
147
148    /* FIXME: check what happens when fseek()ing a pipe */
149    switch(whence)
150    {
151        case SEEK_END:
152            offset = ftell(stream);
153            /* fall through */
154        case SEEK_SET:
155            _zz_setpos(fd, offset);
156            break;
157        case SEEK_CUR:
158            _zz_addpos(fd, offset);
159            break;
160    }
161    return 0;
162}
163
164void rewind(FILE *stream)
165{
166    int fd;
167
168    if(!_zz_ready)
169        LOADSYM(rewind);
170    fd = fileno(stream);
171    if(!_zz_ready || !_zz_iswatched(fd))
172    {
173        rewind_orig(stream);
174        return;
175    }
176
177    _zz_disabled = 1;
178    rewind_orig(stream);
179    _zz_disabled = 0;
180    debug("rewind([%i])", fd);
181
182    /* FIXME: check what happens when rewind()ing a pipe */
183    _zz_setpos(fd, 0);
184}
185
186size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
187{
188    long int pos;
189    size_t ret;
190    int fd;
191
192    if(!_zz_ready)
193        LOADSYM(fread);
194    fd = fileno(stream);
195    if(!_zz_ready || !_zz_iswatched(fd))
196        return fread_orig(ptr, size, nmemb, stream);
197
198    pos = ftell(stream);
199    _zz_disabled = 1;
200    ret = fread_orig(ptr, size, nmemb, stream);
201    _zz_disabled = 0;
202    debug("fread(%p, %li, %li, [%i]) = %li",
203          ptr, (long int)size, (long int)nmemb, fd, (long int)ret);
204    if(ret >= 0)
205    {
206        /* XXX: the number of bytes read is not ret * size, because
207         * a partial read may have advanced the stream pointer. However,
208         * when reading from a pipe ftell() will return 0, and ret * size
209         * is then better than nothing. */
210        long int newpos = ftell(stream);
211        if(newpos <= 0)
212            newpos = ret * size;
213        if(newpos != pos)
214        {
215            _zz_fuzz(fd, ptr, newpos - pos);
216            _zz_setpos(fd, newpos);
217        }
218    }
219    return ret;
220}
221
222#define FGETC(fn) \
223    do { \
224        int fd; \
225        if(!_zz_ready) \
226            LOADSYM(fn); \
227        fd = fileno(stream); \
228        if(!_zz_ready || !_zz_iswatched(fd)) \
229            return ORIG(fn)(stream); \
230        _zz_disabled = 1; \
231        ret = ORIG(fn)(stream); \
232        _zz_disabled = 0; \
233        if(ret != EOF) \
234        { \
235            uint8_t ch = ret; \
236            _zz_fuzz(fd, &ch, 1); \
237            _zz_addpos(fd, 1); \
238            ret = ch; \
239        } \
240        if(ret >= 0x20 && ret <= 0x7f) \
241            debug(STR(fn)"([%i]) = 0x%02x '%c'", fd, ret, (char)ret); \
242        else \
243            debug(STR(fn)"([%i]) = 0x%02x", fd, ret); \
244    } while(0)
245
246#if !defined getc
247int getc(FILE *stream)
248{
249    int ret; FGETC(getc); return ret;
250}
251#endif
252
253int fgetc(FILE *stream)
254{
255    int ret; FGETC(fgetc); return ret;
256}
257
258char *fgets(char *s, int size, FILE *stream)
259{
260    char *ret = s;
261    int i, fd;
262
263    if(!_zz_ready)
264        LOADSYM(fgets);
265    fd = fileno(stream);
266    if(!_zz_ready || !_zz_iswatched(fd))
267        return fgets_orig(s, size, stream);
268
269    if(size <= 0)
270        ret = NULL;
271    else if(size == 1)
272        s[0] = '\0';
273    else
274    {
275        for(i = 0; i < size - 1; i++)
276        {
277            int ch;
278
279            _zz_disabled = 1;
280            ch = fgetc_orig(stream);
281            _zz_disabled = 0;
282
283            if(ch == EOF)
284            {
285                s[i] = '\0';
286                if(!i)
287                    ret = NULL;
288                break;
289            }
290            s[i] = (char)(unsigned char)ch;
291            _zz_fuzz(fd, (uint8_t *)s + i, 1); /* rather inefficient */
292            _zz_addpos(fd, 1);
293            if(s[i] == '\n')
294            {
295                s[i + 1] = '\0';
296                break;
297            }
298        }
299    }
300
301    debug("fgets(%p, %i, [%i]) = %p", s, size, fd, ret);
302    return ret;
303}
304
305int ungetc(int c, FILE *stream)
306{
307    unsigned char ch = c;
308    int ret, fd;
309
310    if(!_zz_ready)
311        LOADSYM(ungetc);
312    fd = fileno(stream);
313    if(!_zz_ready || !_zz_iswatched(fd))
314        return ungetc_orig(c, stream);
315
316    _zz_addpos(fd, -1);
317    _zz_fuzz(fd, &ch, 1);
318    ret = ungetc_orig((int)ch, stream);
319    if(ret >= 0)
320        ret = c;
321    else
322        _zz_addpos(fd, 1); /* revert what we did */
323    if(ret >= 0x20 && ret <= 0x7f)
324        debug("ungetc(0x%02x, [%i]) = 0x%02x '%c'", c, fd, ret, ret);
325    else
326        debug("ungetc(0x%02x, [%i]) = 0x%02x", c, fd, ret);
327    return ret;
328}
329
330int fclose(FILE *fp)
331{
332    int ret, fd;
333
334    if(!_zz_ready)
335        LOADSYM(fclose);
336    fd = fileno(fp);
337    if(!_zz_ready || !_zz_iswatched(fd))
338        return fclose_orig(fp);
339
340    _zz_disabled = 1;
341    ret = fclose_orig(fp);
342    _zz_disabled = 0;
343    debug("fclose([%i]) = %i", fd, ret);
344    _zz_unregister(fd);
345
346    return ret;
347}
348
349#define GETDELIM(fn, delim, need_delim) \
350    do { \
351        char *line; \
352        ssize_t done, size; \
353        int fd, finished = 0; \
354        if(!_zz_ready) \
355            LOADSYM(fn); \
356        fd = fileno(stream); \
357        if(!_zz_ready || !_zz_iswatched(fd)) \
358            return getdelim_orig(lineptr, n, delim, stream); \
359        line = *lineptr; \
360        size = line ? *n : 0; \
361        ret = done = finished = 0; \
362        for(;;) \
363        { \
364            int ch; \
365            if(done >= size) /* highly inefficient but I don't care */ \
366                line = realloc(line, size = done + 1); \
367            if(finished) \
368            { \
369                line[done] = '\0'; \
370                *n = size; \
371                *lineptr = line; \
372                break; \
373            } \
374            _zz_disabled = 1; \
375            ch = fgetc_orig(stream); \
376            _zz_disabled = 0; \
377            if(ch == EOF) \
378            { \
379                finished = 1; \
380                ret = done; \
381            } \
382            else \
383            { \
384                unsigned char c = ch; \
385                _zz_fuzz(fd, &c, 1); /* even more inefficient */ \
386                line[done++] = c; \
387                _zz_addpos(fd, 1); \
388                if(c == delim) \
389                { \
390                    finished = 1; \
391                    ret = done; \
392                } \
393            } \
394        } \
395        if(need_delim) \
396            debug(STR(fn) "(%p, %p, 0x%02x, [%i]) = %li", \
397                  lineptr, n, delim, fd, (long int)ret); \
398        else \
399            debug(STR(fn) "(%p, %p, [%i]) = %li", \
400                  lineptr, n, fd, (long int)ret); \
401        return ret; \
402    } while(0)
403
404#ifdef HAVE_GETLINE
405ssize_t getline(char **lineptr, size_t *n, FILE *stream)
406{
407    ssize_t ret; GETDELIM(getline, '\n', 0); return ret;
408}
409#endif
410
411#ifdef HAVE_GETDELIM
412ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream)
413{
414    ssize_t ret; GETDELIM(getdelim, delim, 1); return ret;
415}
416#endif
417
418#ifdef HAVE___GETDELIM
419ssize_t __getdelim(char **lineptr, size_t *n, int delim, FILE *stream)
420{
421    ssize_t ret; GETDELIM(__getdelim, delim, 1); return ret;
422}
423#endif
424
425#ifdef HAVE_FGETLN
426char *fgetln(FILE *stream, size_t *len)
427{
428    struct fuzz *fuzz;
429    size_t i, size;
430    int fd;
431
432    if(!_zz_ready)
433        LOADSYM(fgetln);
434    fd = fileno(stream);
435    if(!_zz_ready || !_zz_iswatched(fd))
436        return fgetln_orig(stream, len);
437
438    fuzz = _zz_getfuzz(fd);
439
440    for(i = size = 0; ; i++)
441    {
442        int ch;
443
444        _zz_disabled = 1;
445        ch = fgetc_orig(stream);
446        _zz_disabled = 0;
447
448        if(ch == EOF)
449            break;
450
451        if(i >= size)
452            fuzz->tmp = realloc(fuzz->tmp, (size += 80));
453
454        fuzz->tmp[i] = (char)(unsigned char)ch;
455        _zz_fuzz(fd, (uint8_t *)fuzz->tmp + i, 1); /* rather inefficient */
456        _zz_addpos(fd, 1);
457
458        if(fuzz->tmp[i] == '\n')
459            break;
460    }
461
462    *len = i;
463
464    debug("fgetln([%i], &%li) = %p", fd, (long int)*len, fuzz->tmp);
465    return fuzz->tmp;
466}
467#endif
468
Note: See TracBrowser for help on using the repository browser.