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

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