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

Last change on this file since 4251 was 4251, checked in by Sam Hocevar, 11 years ago

Fix compilation warning in lib-fd.c.

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