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

Revision 1591, 11.0 KB checked in by sam, 6 years ago (diff)
  • Cleaned up code.
  • 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, newpos;
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
205    /* XXX: the number of bytes read is not ret * size, because
206     * a partial read may have advanced the stream pointer. However,
207     * when reading from a pipe ftell() will return 0, and ret * size
208     * is then better than nothing. */
209    newpos = ftell(stream);
210    if(newpos <= 0)
211        newpos = ret * size;
212    if(newpos != pos)
213    {
214        _zz_fuzz(fd, ptr, newpos - pos);
215        _zz_setpos(fd, newpos);
216    }
217
218    return ret;
219}
220
221#define FGETC(fn) \
222    do { \
223        int fd; \
224        if(!_zz_ready) \
225            LOADSYM(fn); \
226        fd = fileno(stream); \
227        if(!_zz_ready || !_zz_iswatched(fd)) \
228            return ORIG(fn)(stream); \
229        _zz_disabled = 1; \
230        ret = ORIG(fn)(stream); \
231        _zz_disabled = 0; \
232        if(ret != EOF) \
233        { \
234            uint8_t ch = ret; \
235            _zz_fuzz(fd, &ch, 1); \
236            _zz_addpos(fd, 1); \
237            ret = ch; \
238        } \
239        if(ret >= 0x20 && ret <= 0x7f) \
240            debug(STR(fn)"([%i]) = 0x%02x '%c'", fd, ret, (char)ret); \
241        else \
242            debug(STR(fn)"([%i]) = 0x%02x", fd, ret); \
243    } while(0)
244
245#if !defined getc
246int getc(FILE *stream)
247{
248    int ret; FGETC(getc); return ret;
249}
250#endif
251
252int fgetc(FILE *stream)
253{
254    int ret; FGETC(fgetc); return ret;
255}
256
257char *fgets(char *s, int size, FILE *stream)
258{
259    char *ret = s;
260    int i, fd;
261
262    if(!_zz_ready)
263        LOADSYM(fgets);
264    fd = fileno(stream);
265    if(!_zz_ready || !_zz_iswatched(fd))
266        return fgets_orig(s, size, stream);
267
268    if(size <= 0)
269        ret = NULL;
270    else if(size == 1)
271        s[0] = '\0';
272    else
273    {
274        for(i = 0; i < size - 1; i++)
275        {
276            int ch;
277
278            _zz_disabled = 1;
279            ch = fgetc_orig(stream);
280            _zz_disabled = 0;
281
282            if(ch == EOF)
283            {
284                s[i] = '\0';
285                if(!i)
286                    ret = NULL;
287                break;
288            }
289            s[i] = (char)(unsigned char)ch;
290            _zz_fuzz(fd, (uint8_t *)s + i, 1); /* rather inefficient */
291            _zz_addpos(fd, 1);
292            if(s[i] == '\n')
293            {
294                s[i + 1] = '\0';
295                break;
296            }
297        }
298    }
299
300    debug("fgets(%p, %i, [%i]) = %p", s, size, fd, ret);
301    return ret;
302}
303
304int ungetc(int c, FILE *stream)
305{
306    unsigned char ch = c;
307    int ret, fd;
308
309    if(!_zz_ready)
310        LOADSYM(ungetc);
311    fd = fileno(stream);
312    if(!_zz_ready || !_zz_iswatched(fd))
313        return ungetc_orig(c, stream);
314
315    _zz_addpos(fd, -1);
316    _zz_fuzz(fd, &ch, 1);
317    ret = ungetc_orig((int)ch, stream);
318    if(ret >= 0)
319        ret = c;
320    else
321        _zz_addpos(fd, 1); /* revert what we did */
322    if(ret >= 0x20 && ret <= 0x7f)
323        debug("ungetc(0x%02x, [%i]) = 0x%02x '%c'", c, fd, ret, ret);
324    else
325        debug("ungetc(0x%02x, [%i]) = 0x%02x", c, fd, ret);
326    return ret;
327}
328
329int fclose(FILE *fp)
330{
331    int ret, fd;
332
333    if(!_zz_ready)
334        LOADSYM(fclose);
335    fd = fileno(fp);
336    if(!_zz_ready || !_zz_iswatched(fd))
337        return fclose_orig(fp);
338
339    _zz_disabled = 1;
340    ret = fclose_orig(fp);
341    _zz_disabled = 0;
342    debug("fclose([%i]) = %i", fd, ret);
343    _zz_unregister(fd);
344
345    return ret;
346}
347
348#define GETDELIM(fn, delim, need_delim) \
349    do { \
350        char *line; \
351        ssize_t done, size; \
352        int fd, finished = 0; \
353        if(!_zz_ready) \
354            LOADSYM(fn); \
355        fd = fileno(stream); \
356        if(!_zz_ready || !_zz_iswatched(fd)) \
357            return getdelim_orig(lineptr, n, delim, stream); \
358        line = *lineptr; \
359        size = line ? *n : 0; \
360        ret = done = finished = 0; \
361        for(;;) \
362        { \
363            int ch; \
364            if(done >= size) /* highly inefficient but I don't care */ \
365                line = realloc(line, size = done + 1); \
366            if(finished) \
367            { \
368                line[done] = '\0'; \
369                *n = size; \
370                *lineptr = line; \
371                break; \
372            } \
373            _zz_disabled = 1; \
374            ch = fgetc_orig(stream); \
375            _zz_disabled = 0; \
376            if(ch == EOF) \
377            { \
378                finished = 1; \
379                ret = done; \
380            } \
381            else \
382            { \
383                unsigned char c = ch; \
384                _zz_fuzz(fd, &c, 1); /* even more inefficient */ \
385                line[done++] = c; \
386                _zz_addpos(fd, 1); \
387                if(c == delim) \
388                { \
389                    finished = 1; \
390                    ret = done; \
391                } \
392            } \
393        } \
394        if(need_delim) \
395            debug(STR(fn) "(%p, %p, 0x%02x, [%i]) = %li", \
396                  lineptr, n, delim, fd, (long int)ret); \
397        else \
398            debug(STR(fn) "(%p, %p, [%i]) = %li", \
399                  lineptr, n, fd, (long int)ret); \
400        return ret; \
401    } while(0)
402
403#ifdef HAVE_GETLINE
404ssize_t getline(char **lineptr, size_t *n, FILE *stream)
405{
406    ssize_t ret; GETDELIM(getline, '\n', 0); return ret;
407}
408#endif
409
410#ifdef HAVE_GETDELIM
411ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream)
412{
413    ssize_t ret; GETDELIM(getdelim, delim, 1); return ret;
414}
415#endif
416
417#ifdef HAVE___GETDELIM
418ssize_t __getdelim(char **lineptr, size_t *n, int delim, FILE *stream)
419{
420    ssize_t ret; GETDELIM(__getdelim, delim, 1); return ret;
421}
422#endif
423
424#ifdef HAVE_FGETLN
425char *fgetln(FILE *stream, size_t *len)
426{
427    struct fuzz *fuzz;
428    size_t i, size;
429    int fd;
430
431    if(!_zz_ready)
432        LOADSYM(fgetln);
433    fd = fileno(stream);
434    if(!_zz_ready || !_zz_iswatched(fd))
435        return fgetln_orig(stream, len);
436
437    fuzz = _zz_getfuzz(fd);
438
439    for(i = size = 0; ; i++)
440    {
441        int ch;
442
443        _zz_disabled = 1;
444        ch = fgetc_orig(stream);
445        _zz_disabled = 0;
446
447        if(ch == EOF)
448            break;
449
450        if(i >= size)
451            fuzz->tmp = realloc(fuzz->tmp, (size += 80));
452
453        fuzz->tmp[i] = (char)(unsigned char)ch;
454        _zz_fuzz(fd, (uint8_t *)fuzz->tmp + i, 1); /* rather inefficient */
455        _zz_addpos(fd, 1);
456
457        if(fuzz->tmp[i] == '\n')
458            break;
459    }
460
461    *len = i;
462
463    debug("fgetln([%i], &%li) = %p", fd, (long int)*len, fuzz->tmp);
464    return fuzz->tmp;
465}
466#endif
467
Note: See TracBrowser for help on using the repository browser.