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

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