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

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