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

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