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

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