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

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