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

Last change on this file since 4238 was 4238, checked in by Sam Hocevar, 9 years ago

Fix compilation warning due to kfreebsd’s fcntl.h defining FREAD.

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