source: zzuf/trunk/src/lib-fd.c @ 1718

Last change on this file since 1718 was 1718, checked in by Sam Hocevar, 16 years ago
  • Carry DEBUG_FILENO in the ZZUF_DEBUG environment variable.
  • Property svn:keywords set to Id
File size: 12.5 KB
Line 
1/*
2 *  zzuf - general purpose fuzzer
3 *  Copyright (c) 2006, 2007 Sam Hocevar <sam@zoy.org>
4 *                2007 Rémi Denis-Courmont <rdenis#simphalempin:com>
5 *                2007 Clément Stenac <zorglub#diwi:org>
6 *                2007 Dominik Kuhlen <dominik.kuhlen#gmit-gmbh:de>
7 *                All Rights Reserved
8 *
9 *  $Id: lib-fd.c 1718 2007-01-25 22:34:28Z sam $
10 *
11 *  This program is free software. It comes without any warranty, to
12 *  the extent permitted by applicable law. You can redistribute it
13 *  and/or modify it under the terms of the Do What The Fuck You Want
14 *  To Public License, Version 2, as published by Sam Hocevar. See
15 *  http://sam.zoy.org/wtfpl/COPYING for more details.
16 */
17
18/*
19 *  load-fd.c: loaded file descriptor functions
20 */
21
22#include "config.h"
23
24/* Need this for RTLD_NEXT */
25#define _GNU_SOURCE
26/* Use this to get lseek64() on glibc systems */
27#define _LARGEFILE64_SOURCE
28
29#if defined HAVE_STDINT_H
30#   include <stdint.h>
31#elif defined HAVE_INTTYPES_H
32#   include <inttypes.h>
33#endif
34#include <stdlib.h>
35#include <string.h>
36#include <stdio.h>
37
38#if defined HAVE_WINSOCK2_H
39#   include <winsock2.h>
40#endif
41#include <sys/types.h>
42#if defined HAVE_SYS_SOCKET_H
43#   include <sys/socket.h>
44#endif
45#if defined HAVE_SYS_UIO_H
46#   include <sys/uio.h>
47#endif
48#include <unistd.h>
49#include <fcntl.h>
50#include <stdarg.h>
51#if defined HAVE_AIO_H
52#   include <aio.h>
53#endif
54
55#include "libzzuf.h"
56#include "lib-load.h"
57#include "debug.h"
58#include "fuzz.h"
59#include "fd.h"
60
61#if defined HAVE_SOCKLEN_T
62#   define SOCKLEN_T socklen_t
63#else
64#   define SOCKLEN_T int
65#endif
66
67/* Local prototypes */
68#if defined HAVE_READV || defined HAVE_RECVMSG
69static void fuzz_iovec   (int fd, const struct iovec *iov, ssize_t ret);
70#endif
71static void offset_check (int fd);
72
73/* Library functions that we divert */
74static int     (*ORIG(open))    (const char *file, int oflag, ...);
75#if defined HAVE_OPEN64
76static int     (*ORIG(open64))  (const char *file, int oflag, ...);
77#endif
78#if defined HAVE_ACCEPT
79static int     (*ORIG(accept))  (int sockfd, struct sockaddr *addr,
80                                 SOCKLEN_T *addrlen);
81#endif
82#if defined HAVE_SOCKET
83static int     (*ORIG(socket))  (int domain, int type, int protocol);
84#endif
85#if defined HAVE_RECV
86static RECV_T  (*ORIG(recv))    (int s, void *buf, size_t len, int flags);
87#endif
88#if defined HAVE_RECVFROM
89static RECV_T  (*ORIG(recvfrom))(int s, void *buf, size_t len, int flags,
90                                 struct sockaddr *from, SOCKLEN_T *fromlen);
91#endif
92#if defined HAVE_RECVMSG
93static RECV_T  (*ORIG(recvmsg)) (int s,  struct msghdr *hdr, int flags);
94#endif
95#if defined READ_USES_SSIZE_T
96static ssize_t (*ORIG(read))    (int fd, void *buf, size_t count);
97#else
98static int     (*ORIG(read))    (int fd, void *buf, unsigned int count);
99#endif
100#if defined HAVE_READV
101static ssize_t (*ORIG(readv))   (int fd, const struct iovec *iov, int count);
102#endif
103#if defined HAVE_PREAD
104static ssize_t (*ORIG(pread))   (int fd, void *buf, size_t count, off_t offset);
105#endif
106#if defined HAVE_AIO_READ
107static int     (*ORIG(aio_read))   (struct aiocb *aiocbp);
108static ssize_t (*ORIG(aio_return)) (struct aiocb *aiocbp);
109#endif
110static off_t   (*ORIG(lseek))   (int fd, off_t offset, int whence);
111#if defined HAVE_LSEEK64
112static off64_t (*ORIG(lseek64)) (int fd, off64_t offset, int whence);
113#endif
114static int     (*ORIG(close))   (int fd);
115
116#define OPEN(fn) \
117    do \
118    { \
119        int mode = 0; \
120        LOADSYM(fn); \
121        if(oflag & O_CREAT) \
122        { \
123            va_list va; \
124            va_start(va, oflag); \
125            mode = va_arg(va, int); \
126            va_end(va); \
127            ret = ORIG(fn)(file, oflag, mode); \
128        } \
129        else \
130        { \
131            ret = ORIG(fn)(file, oflag); \
132        } \
133        if(!_zz_ready || _zz_islocked(-1)) \
134            return ret; \
135        if(ret >= 0 \
136            && ((oflag & (O_RDONLY | O_RDWR | O_WRONLY)) != O_WRONLY) \
137            && _zz_mustwatch(file)) \
138        { \
139            if(oflag & O_CREAT) \
140                debug("%s(\"%s\", %i, %i) = %i", \
141                      __func__, file, oflag, mode, ret); \
142            else \
143                debug("%s(\"%s\", %i) = %i", __func__, file, oflag, ret); \
144            _zz_register(ret); \
145        } \
146    } while(0)
147
148int NEW(open)(const char *file, int oflag, ...)
149{
150    int ret; OPEN(open); return ret;
151}
152
153#if defined HAVE_OPEN64
154int NEW(open64)(const char *file, int oflag, ...)
155{
156    int ret; OPEN(open64); return ret;
157}
158#endif
159
160#if defined HAVE_ACCEPT
161int NEW(accept)(int sockfd, struct sockaddr *addr, SOCKLEN_T *addrlen)
162{
163    int ret;
164
165    LOADSYM(accept);
166    ret = ORIG(accept)(sockfd, addr, addrlen);
167    if(!_zz_ready || _zz_islocked(-1) || !_zz_network)
168        return ret;
169
170    if(ret >= 0)
171    {
172        debug("%s(%i, %p, %p) = %i", __func__, sockfd, addr, addrlen, ret);
173        _zz_register(ret);
174    }
175
176    return ret;
177}
178#endif
179
180#if defined HAVE_SOCKET
181int NEW(socket)(int domain, int type, int protocol)
182{
183    int ret;
184
185    LOADSYM(socket);
186    ret = ORIG(socket)(domain, type, protocol);
187    if(!_zz_ready || _zz_islocked(-1) || !_zz_network)
188        return ret;
189
190    if(ret >= 0)
191    {
192        debug("%s(%i, %i, %i) = %i", __func__, domain, type, protocol, ret);
193        _zz_register(ret);
194    }
195
196    return ret;
197}
198#endif
199
200#if defined HAVE_RECV
201RECV_T NEW(recv)(int s, void *buf, size_t len, int flags)
202{
203    int ret;
204
205    LOADSYM(recv);
206    ret = ORIG(recv)(s, buf, len, flags);
207    if(!_zz_ready || !_zz_iswatched(s) || _zz_islocked(s))
208        return ret;
209
210    if(ret > 0)
211    {
212        char *b = buf;
213
214        _zz_fuzz(s, buf, ret);
215        _zz_addpos(s, ret);
216
217        if(ret >= 4)
218            debug("%s(%i, %p, %li, 0x%x) = %i \"%c%c%c%c...", __func__,
219                  s, buf, (long int)len, flags, ret, b[0], b[1], b[2], b[3]);
220        else
221            debug("%s(%i, %p, %li, 0x%x) = %i \"%c...", __func__,
222                  s, buf, (long int)len, flags, ret, b[0]);
223    }
224    else
225        debug("%s(%i, %p, %li, 0x%x) = %i", __func__,
226              s, buf, (long int)len, flags, ret);
227
228    return ret;
229}
230#endif
231
232#if defined HAVE_RECVFROM
233RECV_T NEW(recvfrom)(int s, void *buf, size_t len, int flags,
234                     struct sockaddr *from, SOCKLEN_T *fromlen)
235{
236    int ret;
237
238    LOADSYM(recvfrom);
239    ret = ORIG(recvfrom)(s, buf, len, flags, from, fromlen);
240    if(!_zz_ready || !_zz_iswatched(s) || _zz_islocked(s))
241        return ret;
242
243    if(ret > 0)
244    {
245        char *b = buf;
246
247        _zz_fuzz(s, buf, ret);
248        _zz_addpos(s, ret);
249
250        if(ret >= 4)
251            debug("%s(%i, %p, %li, 0x%x, %p, %p) = %i \"%c%c%c%c...", __func__,
252                  s, buf, (long int)len, flags, from, fromlen, ret,
253                  b[0], b[1], b[2], b[3]);
254        else
255            debug("%s(%i, %p, %li, 0x%x, %p, %p) = %i \"%c...", __func__,
256                  s, buf, (long int)len, flags, from, fromlen, ret, b[0]);
257    }
258    else
259        debug("%s(%i, %p, %li, 0x%x, %p, %p) = %i", __func__,
260              s, buf, (long int)len, flags, from, fromlen, ret);
261
262    return ret;
263}
264#endif
265
266#if defined HAVE_RECVMSG
267RECV_T NEW(recvmsg)(int s, struct msghdr *hdr, int flags)
268{
269    ssize_t ret;
270
271    LOADSYM(recvmsg);
272    ret = ORIG(recvmsg)(s, hdr, flags);
273    if(!_zz_ready || !_zz_iswatched(s) || _zz_islocked(s))
274        return ret;
275
276    fuzz_iovec(s, hdr->msg_iov, ret);
277    debug("%s(%i, %p, %x) = %li", __func__, s, hdr, flags, (long int)ret);
278
279    return ret;
280}
281#endif
282
283#if defined READ_USES_SSIZE_T
284ssize_t NEW(read)(int fd, void *buf, size_t count)
285#else
286int NEW(read)(int fd, void *buf, unsigned int count)
287#endif
288{
289    int ret;
290
291    LOADSYM(read);
292    ret = ORIG(read)(fd, buf, count);
293    if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd))
294        return ret;
295
296    if(ret > 0)
297    {
298        char *b = buf;
299
300        _zz_fuzz(fd, buf, ret);
301        _zz_addpos(fd, ret);
302
303        if(ret >= 4)
304            debug("%s(%i, %p, %li) = %i \"%c%c%c%c...", __func__, fd, buf,
305                  (long int)count, ret, b[0], b[1], b[2], b[3]);
306        else
307            debug("%s(%i, %p, %li) = %i \"%c...", __func__, fd, buf,
308                  (long int)count, ret, b[0]);
309    }
310    else
311        debug("%s(%i, %p, %li) = %i", __func__, fd, buf, (long int)count, ret);
312
313    offset_check(fd);
314    return ret;
315}
316
317#if defined HAVE_READV
318ssize_t NEW(readv)(int fd, const struct iovec *iov, int count)
319{
320    ssize_t ret;
321
322    LOADSYM(readv);
323    ret = ORIG(readv)(fd, iov, count);
324    if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd))
325        return ret;
326
327    fuzz_iovec(fd, iov, ret);
328    debug("%s(%i, %p, %i) = %li", __func__, fd, iov, count, (long int)ret);
329
330    offset_check(fd);
331    return ret;
332}
333#endif
334
335#if defined HAVE_PREAD
336ssize_t NEW(pread)(int fd, void *buf, size_t count, off_t offset)
337{
338    int ret;
339
340    LOADSYM(pread);
341    ret = ORIG(pread)(fd, buf, count, offset);
342    if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd))
343        return ret;
344
345    if(ret > 0)
346    {
347        long int curoff = _zz_getpos(fd);
348        char *b = buf;
349
350        _zz_setpos(fd, offset);
351        _zz_fuzz(fd, buf, ret);
352        _zz_setpos(fd, curoff);
353
354        if(ret >= 4)
355            debug("%s(%i, %p, %li, %li) = %i \"%c%c%c%c...", __func__, fd, buf,
356                  (long int)count, (long int)offset, ret,
357                  b[0], b[1], b[2], b[3]);
358        else
359            debug("%s(%i, %p, %li, %li) = %i \"%c...", __func__, fd, buf,
360                  (long int)count, (long int)offset, ret, b[0]);
361    }
362    else
363        debug("%s(%i, %p, %li, %li) = %i", __func__, fd, buf,
364              (long int)count, (long int)offset, ret);
365
366    return ret;
367}
368#endif
369
370#define LSEEK(fn, off_t) \
371    do \
372    { \
373        LOADSYM(fn); \
374        ret = ORIG(fn)(fd, offset, whence); \
375        if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd)) \
376            return ret; \
377        debug("%s(%i, %lli, %i) = %lli", __func__, fd, \
378              (long long int)offset, whence, (long long int)ret); \
379        if(ret != (off_t)-1) \
380            _zz_setpos(fd, ret); \
381    } while(0)
382
383off_t NEW(lseek)(int fd, off_t offset, int whence)
384{
385    off_t ret;
386    LSEEK(lseek, off_t);
387    return ret;
388}
389
390#if defined HAVE_LSEEK64
391off64_t NEW(lseek64)(int fd, off64_t offset, int whence)
392{
393    off64_t ret;
394    LSEEK(lseek64, off64_t);
395    return ret;
396}
397#endif
398
399#if defined HAVE_AIO_READ
400int NEW(aio_read)(struct aiocb *aiocbp)
401{
402    int ret;
403    int fd = aiocbp->aio_fildes;
404
405    LOADSYM(aio_read);
406    if(!_zz_ready || !_zz_iswatched(fd))
407        return ORIG(aio_read)(aiocbp);
408
409    _zz_lock(fd);
410    ret = ORIG(aio_read)(aiocbp);
411
412    debug("%s({%i, %i, %i, %p, %li, ..., %li}) = %i", __func__,
413          fd, aiocbp->aio_lio_opcode, aiocbp->aio_reqprio, aiocbp->aio_buf,
414          (long int)aiocbp->aio_nbytes, (long int)aiocbp->aio_offset, ret);
415
416    return ret;
417}
418
419ssize_t NEW(aio_return)(struct aiocb *aiocbp)
420{
421    ssize_t ret;
422    int fd = aiocbp->aio_fildes;
423
424    LOADSYM(aio_return);
425    if(!_zz_ready || !_zz_iswatched(fd))
426        return ORIG(aio_return)(aiocbp);
427
428    ret = ORIG(aio_return)(aiocbp);
429    _zz_unlock(fd);
430
431    /* FIXME: make sure we’re actually *reading* */
432    if(ret > 0)
433    {
434        _zz_setpos(fd, aiocbp->aio_offset);
435        _zz_fuzz(fd, aiocbp->aio_buf, ret);
436        _zz_addpos(fd, ret);
437    }
438
439    debug("%s({%i, %i, %i, %p, %li, ..., %li}) = %li", __func__,
440          fd, aiocbp->aio_lio_opcode, aiocbp->aio_reqprio, aiocbp->aio_buf,
441          (long int)aiocbp->aio_nbytes, (long int)aiocbp->aio_offset,
442          (long int)ret);
443
444    return ret;
445}
446#endif
447
448int NEW(close)(int fd)
449{
450    int ret;
451
452    /* Hey, it’s our debug channel! Silently pretend we closed it. */
453    if(fd == _zz_debugfd)
454        return 0;
455
456    LOADSYM(close);
457    ret = ORIG(close)(fd);
458    if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd))
459        return ret;
460
461    debug("%s(%i) = %i", __func__, fd, ret);
462    _zz_unregister(fd);
463
464    return ret;
465}
466
467/* XXX: the following functions are local */
468
469#if defined HAVE_READV || defined HAVE_RECVMSG
470static void fuzz_iovec(int fd, const struct iovec *iov, ssize_t ret)
471{
472    /* NOTE: We assume that iov countains at least <ret> bytes. */
473    while(ret > 0)
474    {
475        void *b = iov->iov_base;
476        size_t len = iov->iov_len;
477
478        if(len > (size_t)ret)
479            len = ret;
480
481        _zz_fuzz(fd, b, len);
482        _zz_addpos(fd, len);
483
484        iov++;
485        ret -= len;
486    }
487}
488#endif
489
490static void offset_check(int fd)
491{
492    /* Sanity check, can be OK though (for instance with a character device) */
493#if defined HAVE_LSEEK64
494    off64_t ret;
495    LOADSYM(lseek64);
496    ret = ORIG(lseek64)(fd, 0, SEEK_CUR);
497#else
498    off_t ret;
499    LOADSYM(lseek);
500    ret = ORIG(lseek)(fd, 0, SEEK_CUR);
501#endif
502    if(ret != -1 && ret != _zz_getpos(fd))
503        debug("warning: offset inconsistency");
504}
505
Note: See TracBrowser for help on using the repository browser.