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

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