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

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