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

Last change on this file since 1763 was 1763, checked in by Sam Hocevar, 15 years ago
  • Save errno in offset_check, thanks to Sami Liedes.
  • 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 1763 2007-03-01 23:53:51Z 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))
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))
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))
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        return ret;
298
299    if(ret > 0)
300    {
301        char *b = buf;
302
303        _zz_fuzz(fd, buf, ret);
304        _zz_addpos(fd, ret);
305
306        if(ret >= 4)
307            debug("%s(%i, %p, %li) = %i \"%c%c%c%c...", __func__, fd, buf,
308                  (long int)count, ret, b[0], b[1], b[2], b[3]);
309        else
310            debug("%s(%i, %p, %li) = %i \"%c...", __func__, fd, buf,
311                  (long int)count, ret, b[0]);
312    }
313    else
314        debug("%s(%i, %p, %li) = %i", __func__, fd, buf, (long int)count, ret);
315
316    offset_check(fd);
317    return ret;
318}
319
320#if defined HAVE_READV
321ssize_t NEW(readv)(int fd, const struct iovec *iov, int count)
322{
323    ssize_t ret;
324
325    LOADSYM(readv);
326    ret = ORIG(readv)(fd, iov, count);
327    if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd))
328        return ret;
329
330    fuzz_iovec(fd, iov, ret);
331    debug("%s(%i, %p, %i) = %li", __func__, fd, iov, count, (long int)ret);
332
333    offset_check(fd);
334    return ret;
335}
336#endif
337
338#if defined HAVE_PREAD
339ssize_t NEW(pread)(int fd, void *buf, size_t count, off_t offset)
340{
341    int ret;
342
343    LOADSYM(pread);
344    ret = ORIG(pread)(fd, buf, count, offset);
345    if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd))
346        return ret;
347
348    if(ret > 0)
349    {
350        long int curoff = _zz_getpos(fd);
351        char *b = buf;
352
353        _zz_setpos(fd, offset);
354        _zz_fuzz(fd, buf, ret);
355        _zz_setpos(fd, curoff);
356
357        if(ret >= 4)
358            debug("%s(%i, %p, %li, %li) = %i \"%c%c%c%c...", __func__, fd, buf,
359                  (long int)count, (long int)offset, ret,
360                  b[0], b[1], b[2], b[3]);
361        else
362            debug("%s(%i, %p, %li, %li) = %i \"%c...", __func__, fd, buf,
363                  (long int)count, (long int)offset, ret, b[0]);
364    }
365    else
366        debug("%s(%i, %p, %li, %li) = %i", __func__, fd, buf,
367              (long int)count, (long int)offset, ret);
368
369    return ret;
370}
371#endif
372
373#define LSEEK(fn, off_t) \
374    do \
375    { \
376        LOADSYM(fn); \
377        ret = ORIG(fn)(fd, offset, whence); \
378        if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd)) \
379            return ret; \
380        debug("%s(%i, %lli, %i) = %lli", __func__, fd, \
381              (long long int)offset, whence, (long long int)ret); \
382        if(ret != (off_t)-1) \
383            _zz_setpos(fd, ret); \
384    } while(0)
385
386off_t NEW(lseek)(int fd, off_t offset, int whence)
387{
388    off_t ret;
389    LSEEK(lseek, off_t);
390    return ret;
391}
392
393#if defined HAVE_LSEEK64
394off64_t NEW(lseek64)(int fd, off64_t offset, int whence)
395{
396    off64_t ret;
397    LSEEK(lseek64, off64_t);
398    return ret;
399}
400#endif
401
402#if defined HAVE_AIO_READ
403int NEW(aio_read)(struct aiocb *aiocbp)
404{
405    int ret;
406    int fd = aiocbp->aio_fildes;
407
408    LOADSYM(aio_read);
409    if(!_zz_ready || !_zz_iswatched(fd))
410        return ORIG(aio_read)(aiocbp);
411
412    _zz_lock(fd);
413    ret = ORIG(aio_read)(aiocbp);
414
415    debug("%s({%i, %i, %i, %p, %li, ..., %li}) = %i", __func__,
416          fd, aiocbp->aio_lio_opcode, aiocbp->aio_reqprio, aiocbp->aio_buf,
417          (long int)aiocbp->aio_nbytes, (long int)aiocbp->aio_offset, ret);
418
419    return ret;
420}
421
422ssize_t NEW(aio_return)(struct aiocb *aiocbp)
423{
424    ssize_t ret;
425    int fd = aiocbp->aio_fildes;
426
427    LOADSYM(aio_return);
428    if(!_zz_ready || !_zz_iswatched(fd))
429        return ORIG(aio_return)(aiocbp);
430
431    ret = ORIG(aio_return)(aiocbp);
432    _zz_unlock(fd);
433
434    /* FIXME: make sure we’re actually *reading* */
435    if(ret > 0)
436    {
437        _zz_setpos(fd, aiocbp->aio_offset);
438        _zz_fuzz(fd, aiocbp->aio_buf, ret);
439        _zz_addpos(fd, ret);
440    }
441
442    debug("%s({%i, %i, %i, %p, %li, ..., %li}) = %li", __func__,
443          fd, aiocbp->aio_lio_opcode, aiocbp->aio_reqprio, aiocbp->aio_buf,
444          (long int)aiocbp->aio_nbytes, (long int)aiocbp->aio_offset,
445          (long int)ret);
446
447    return ret;
448}
449#endif
450
451int NEW(close)(int fd)
452{
453    int ret;
454
455    /* Hey, it’s our debug channel! Silently pretend we closed it. */
456    if(fd == _zz_debugfd)
457        return 0;
458
459    LOADSYM(close);
460    ret = ORIG(close)(fd);
461    if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd))
462        return ret;
463
464    debug("%s(%i) = %i", __func__, fd, ret);
465    _zz_unregister(fd);
466
467    return ret;
468}
469
470/* XXX: the following functions are local */
471
472#if defined HAVE_READV || defined HAVE_RECVMSG
473static void fuzz_iovec(int fd, const struct iovec *iov, ssize_t ret)
474{
475    /* NOTE: We assume that iov countains at least <ret> bytes. */
476    while(ret > 0)
477    {
478        void *b = iov->iov_base;
479        size_t len = iov->iov_len;
480
481        if(len > (size_t)ret)
482            len = ret;
483
484        _zz_fuzz(fd, b, len);
485        _zz_addpos(fd, len);
486
487        iov++;
488        ret -= len;
489    }
490}
491#endif
492
493/* Sanity check, can be OK though (for instance with a character device) */
494static void offset_check(int fd)
495{
496    int orig_errno = errno;
497#if defined HAVE_LSEEK64
498    off64_t ret;
499    LOADSYM(lseek64);
500    ret = ORIG(lseek64)(fd, 0, SEEK_CUR);
501#else
502    off_t ret;
503    LOADSYM(lseek);
504    ret = ORIG(lseek)(fd, 0, SEEK_CUR);
505#endif
506    if(ret != -1 && ret != _zz_getpos(fd))
507        debug("warning: offset inconsistency");
508    errno = orig_errno;
509}
510
Note: See TracBrowser for help on using the repository browser.