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

Last change on this file since 4253 was 4253, checked in by sam, 4 years ago

Fix copyright information and remove Id tag everywhere.

  • 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 *  This program is free software. It comes without any warranty, to
11 *  the extent permitted by applicable law. You can redistribute it
12 *  and/or modify it under the terms of the Do What The Fuck You Want
13 *  To Public License, Version 2, as published by Sam Hocevar. See
14 *  http://sam.zoy.org/wtfpl/COPYING for more details.
15 */
16
17/*
18 *  load-fd.c: loaded file descriptor functions
19 */
20
21#include "config.h"
22
23/* Need this for RTLD_NEXT */
24#define _GNU_SOURCE
25/* Use this to get lseek64() on glibc systems */
26#define _LARGEFILE64_SOURCE
27/* Use this to get proper prototypes on HP-UX systems */
28#define _XOPEN_SOURCE_EXTENDED
29#define _INCLUDE_POSIX_SOURCE
30
31#if defined HAVE_STDINT_H
32#   include <stdint.h>
33#elif defined HAVE_INTTYPES_H
34#   include <inttypes.h>
35#endif
36#include <stdlib.h>
37#include <string.h>
38#include <stdio.h>
39#include <errno.h>
40
41#if defined HAVE_WINSOCK2_H
42#   include <winsock2.h>
43#endif
44#include <sys/types.h>
45#if defined HAVE_SYS_SOCKET_H
46#   include <sys/socket.h>
47#endif
48#if defined HAVE_NETINET_IN_H
49#   include <netinet/in.h>
50#endif
51#if defined HAVE_ARPA_INET_H
52#   include <arpa/inet.h>
53#endif
54#if defined HAVE_SYS_UIO_H
55#   include <sys/uio.h>
56#endif
57#if defined HAVE_UNISTD_H
58#   include <unistd.h>
59#endif
60#include <fcntl.h>
61#include <stdarg.h>
62#if defined HAVE_AIO_H
63#   include <aio.h>
64#endif
65
66#include "libzzuf.h"
67#include "lib-load.h"
68#include "debug.h"
69#include "network.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 ZZ_OPEN(myopen) \
149    do \
150    { \
151        int mode = 0; \
152        LOADSYM(myopen); \
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(myopen)(file, oflag, mode); \
160        } \
161        else \
162        { \
163            ret = ORIG(myopen)(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; ZZ_OPEN(open); return ret;
183}
184
185#if defined HAVE_OPEN64
186int NEW(open64)(const char *file, int oflag, ...)
187{
188    int ret; ZZ_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; ZZ_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        if(addrlen)
260            debug("%s(%i, %p, &%i) = %i", __func__,
261                  sockfd, addr, (int)*addrlen, ret);
262        else
263            debug("%s(%i, %p, NULL) = %i", __func__, sockfd, addr, ret);
264        _zz_register(ret);
265    }
266
267    return ret;
268}
269#endif
270
271#if defined AF_INET6
272#   define case_AF_INET6 case AF_INET6:
273#else
274#   define case_AF_INET6
275#endif
276
277#define ZZ_CONNECT(myconnect, addr) \
278    do \
279    { \
280        LOADSYM(myconnect); \
281        ret = ORIG(myconnect)(sockfd, addr, addrlen); \
282        if(!_zz_ready || _zz_islocked(-1) || !_zz_network) \
283            return ret; \
284        if(ret >= 0) \
285        { \
286            struct sockaddr_in in; \
287            long int port; \
288            switch(addr->sa_family) \
289            { \
290            case AF_INET: \
291            case_AF_INET6 \
292                /* We need to copy rather than cast sockaddr* to sockaddr_in* \
293                 * because sockaddr_in* has actually _larger_ alignment on \
294                 * eg. Linux alpha. And we only need sin_port so we only copy \
295                 * this member. */ \
296                memcpy(&in.sin_port, \
297                   (char const *)addr + ((char *)&in.sin_port - (char *)&in), \
298                   sizeof(in.sin_port)); \
299                port = ntohs(in.sin_port); \
300                if(_zz_portwatched(port)) \
301                    break; \
302                /* Fall through */ \
303            default: \
304                _zz_unregister(sockfd); \
305                return ret; \
306            } \
307            debug("%s(%i, %p, %i) = %i", __func__, \
308                  sockfd, addr, (int)addrlen, ret); \
309        } \
310    } while(0);
311
312#if defined HAVE_BIND
313int NEW(bind)(int sockfd, const struct sockaddr *my_addr, SOCKLEN_T addrlen)
314{
315    int ret; ZZ_CONNECT(bind, my_addr); return ret;
316}
317#endif
318
319#if defined HAVE_CONNECT
320int NEW(connect)(int sockfd, const struct sockaddr *serv_addr,
321                 SOCKLEN_T addrlen)
322{
323    int ret; ZZ_CONNECT(connect, serv_addr); return ret;
324}
325#endif
326
327#if defined HAVE_SOCKET
328int NEW(socket)(int domain, int type, int protocol)
329{
330    int ret;
331
332    LOADSYM(socket);
333    ret = ORIG(socket)(domain, type, protocol);
334    if(!_zz_ready || _zz_islocked(-1) || !_zz_network)
335        return ret;
336
337    if(ret >= 0)
338    {
339        debug("%s(%i, %i, %i) = %i", __func__, domain, type, protocol, ret);
340        _zz_register(ret);
341    }
342
343    return ret;
344}
345#endif
346
347#if defined HAVE_RECV
348RECV_T NEW(recv)(int s, void *buf, size_t len, int flags)
349{
350    int ret;
351
352    LOADSYM(recv);
353    ret = ORIG(recv)(s, buf, len, flags);
354    if(!_zz_ready || !_zz_iswatched(s) || !_zz_hostwatched(s)
355         || _zz_islocked(s) || !_zz_isactive(s))
356        return ret;
357
358    if(ret > 0)
359    {
360        char *b = buf;
361
362        _zz_fuzz(s, buf, ret);
363        _zz_addpos(s, ret);
364
365        if(ret >= 4)
366            debug("%s(%i, %p, %li, 0x%x) = %i \"%c%c%c%c...", __func__,
367                  s, buf, (long int)len, flags, ret, b[0], b[1], b[2], b[3]);
368        else
369            debug("%s(%i, %p, %li, 0x%x) = %i \"%c...", __func__,
370                  s, buf, (long int)len, flags, ret, b[0]);
371    }
372    else
373        debug("%s(%i, %p, %li, 0x%x) = %i", __func__,
374              s, buf, (long int)len, flags, ret);
375
376    return ret;
377}
378#endif
379
380#if defined HAVE_RECVFROM
381RECV_T NEW(recvfrom)(int s, void *buf, size_t len, int flags,
382                     struct sockaddr *from, SOCKLEN_T *fromlen)
383{
384    int ret;
385
386    LOADSYM(recvfrom);
387    ret = ORIG(recvfrom)(s, buf, len, flags, from, fromlen);
388    if(!_zz_ready || !_zz_iswatched(s) || !_zz_hostwatched(s)
389         || _zz_islocked(s) || !_zz_isactive(s))
390        return ret;
391
392    if(ret > 0)
393    {
394        char tmp[128];
395        char *b = buf;
396
397        _zz_fuzz(s, buf, ret);
398        _zz_addpos(s, ret);
399
400        if (fromlen)
401            sprintf(tmp, "&%i", (int)*fromlen);
402        else
403            strcpy(tmp, "NULL");
404
405        if (ret >= 4)
406            debug("%s(%i, %p, %li, 0x%x, %p, %s) = %i \"%c%c%c%c...",
407                  __func__, s, buf, (long int)len, flags, from, tmp,
408                  ret, b[0], b[1], b[2], b[3]);
409        else
410            debug("%s(%i, %p, %li, 0x%x, %p, %s) = %i \"%c...",
411                  __func__, s, buf, (long int)len, flags, from, tmp,
412                  ret, b[0]);
413    }
414    else
415        debug("%s(%i, %p, %li, 0x%x, %p, %p) = %i", __func__,
416              s, buf, (long int)len, flags, from, fromlen, ret);
417
418    return ret;
419}
420#endif
421
422#if defined HAVE_RECVMSG
423RECV_T NEW(recvmsg)(int s, struct msghdr *hdr, int flags)
424{
425    ssize_t ret;
426
427    LOADSYM(recvmsg);
428    ret = ORIG(recvmsg)(s, hdr, flags);
429    if(!_zz_ready || !_zz_iswatched(s) || !_zz_hostwatched(s)
430         || _zz_islocked(s) || !_zz_isactive(s))
431        return ret;
432
433    fuzz_iovec(s, hdr->msg_iov, ret);
434    debug("%s(%i, %p, %x) = %li", __func__, s, hdr, flags, (long int)ret);
435
436    return ret;
437}
438#endif
439
440#if defined READ_USES_SSIZE_T
441ssize_t NEW(read)(int fd, void *buf, size_t count)
442#else
443int NEW(read)(int fd, void *buf, unsigned int count)
444#endif
445{
446    int ret;
447
448    LOADSYM(read);
449    ret = ORIG(read)(fd, buf, count);
450    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_hostwatched(fd)
451         || _zz_islocked(fd) || !_zz_isactive(fd))
452        return ret;
453
454    if(ret > 0)
455    {
456        char *b = buf;
457
458        _zz_fuzz(fd, buf, ret);
459        _zz_addpos(fd, ret);
460
461        if(ret >= 4)
462            debug("%s(%i, %p, %li) = %i \"%c%c%c%c...", __func__, fd, buf,
463                  (long int)count, ret, b[0], b[1], b[2], b[3]);
464        else
465            debug("%s(%i, %p, %li) = %i \"%c...", __func__, fd, buf,
466                  (long int)count, ret, b[0]);
467    }
468    else
469        debug("%s(%i, %p, %li) = %i", __func__, fd, buf, (long int)count, ret);
470
471    offset_check(fd);
472    return ret;
473}
474
475#if defined HAVE_READV
476ssize_t NEW(readv)(int fd, const struct iovec *iov, int count)
477{
478    ssize_t ret;
479
480    LOADSYM(readv);
481    ret = ORIG(readv)(fd, iov, count);
482    if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd)
483         || !_zz_isactive(fd))
484        return ret;
485
486    fuzz_iovec(fd, iov, ret);
487    debug("%s(%i, %p, %i) = %li", __func__, fd, iov, count, (long int)ret);
488
489    offset_check(fd);
490    return ret;
491}
492#endif
493
494#if defined HAVE_PREAD
495ssize_t NEW(pread)(int fd, void *buf, size_t count, off_t offset)
496{
497    int ret;
498
499    LOADSYM(pread);
500    ret = ORIG(pread)(fd, buf, count, offset);
501    if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd)
502         || !_zz_isactive(fd))
503        return ret;
504
505    if(ret > 0)
506    {
507        long int curoff = _zz_getpos(fd);
508        char *b = buf;
509
510        _zz_setpos(fd, offset);
511        _zz_fuzz(fd, buf, ret);
512        _zz_setpos(fd, curoff);
513
514        if(ret >= 4)
515            debug("%s(%i, %p, %li, %li) = %i \"%c%c%c%c...", __func__, fd, buf,
516                  (long int)count, (long int)offset, ret,
517                  b[0], b[1], b[2], b[3]);
518        else
519            debug("%s(%i, %p, %li, %li) = %i \"%c...", __func__, fd, buf,
520                  (long int)count, (long int)offset, ret, b[0]);
521    }
522    else
523        debug("%s(%i, %p, %li, %li) = %i", __func__, fd, buf,
524              (long int)count, (long int)offset, ret);
525
526    return ret;
527}
528#endif
529
530#define ZZ_LSEEK(mylseek, off_t) \
531    do \
532    { \
533        LOADSYM(mylseek); \
534        ret = ORIG(mylseek)(fd, offset, whence); \
535        if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd) \
536             || !_zz_isactive(fd)) \
537            return ret; \
538        debug("%s(%i, %lli, %i) = %lli", __func__, fd, \
539              (long long int)offset, whence, (long long int)ret); \
540        if(ret != (off_t)-1) \
541            _zz_setpos(fd, ret); \
542    } while(0)
543
544off_t NEW(lseek)(int fd, off_t offset, int whence)
545{
546    off_t ret;
547    ZZ_LSEEK(lseek, off_t);
548    return ret;
549}
550
551#if defined HAVE_LSEEK64
552off64_t NEW(lseek64)(int fd, off64_t offset, int whence)
553{
554    off64_t ret; ZZ_LSEEK(lseek64, off64_t); return ret;
555}
556#endif
557
558#if defined HAVE___LSEEK64
559off64_t NEW(__lseek64)(int fd, off64_t offset, int whence)
560{
561    off64_t ret; ZZ_LSEEK(__lseek64, off64_t); return ret;
562}
563#endif
564
565#if defined HAVE_AIO_READ
566int NEW(aio_read)(struct aiocb *aiocbp)
567{
568    int ret;
569    int fd = aiocbp->aio_fildes;
570
571    LOADSYM(aio_read);
572    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
573        return ORIG(aio_read)(aiocbp);
574
575    _zz_lock(fd);
576    ret = ORIG(aio_read)(aiocbp);
577
578    debug("%s({%i, %i, %i, %p, %li, ..., %li}) = %i", __func__,
579          fd, aiocbp->aio_lio_opcode, aiocbp->aio_reqprio, aiocbp->aio_buf,
580          (long int)aiocbp->aio_nbytes, (long int)aiocbp->aio_offset, ret);
581
582    return ret;
583}
584
585ssize_t NEW(aio_return)(struct aiocb *aiocbp)
586{
587    ssize_t ret;
588    int fd = aiocbp->aio_fildes;
589
590    LOADSYM(aio_return);
591    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
592        return ORIG(aio_return)(aiocbp);
593
594    ret = ORIG(aio_return)(aiocbp);
595    _zz_unlock(fd);
596
597    /* FIXME: make sure we’re actually *reading* */
598    if(ret > 0)
599    {
600        _zz_setpos(fd, aiocbp->aio_offset);
601        _zz_fuzz(fd, aiocbp->aio_buf, ret);
602        _zz_addpos(fd, ret);
603    }
604
605    debug("%s({%i, %i, %i, %p, %li, ..., %li}) = %li", __func__,
606          fd, aiocbp->aio_lio_opcode, aiocbp->aio_reqprio, aiocbp->aio_buf,
607          (long int)aiocbp->aio_nbytes, (long int)aiocbp->aio_offset,
608          (long int)ret);
609
610    return ret;
611}
612#endif
613
614int NEW(close)(int fd)
615{
616    int ret;
617
618    /* Hey, it’s our debug channel! Silently pretend we closed it. */
619    if(fd == _zz_debugfd)
620        return 0;
621
622    LOADSYM(close);
623    ret = ORIG(close)(fd);
624    if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd))
625        return ret;
626
627    debug("%s(%i) = %i", __func__, fd, ret);
628    _zz_unregister(fd);
629
630    return ret;
631}
632
633/* XXX: the following functions are local */
634
635#if defined HAVE_READV || defined HAVE_RECVMSG
636static void fuzz_iovec(int fd, const struct iovec *iov, ssize_t ret)
637{
638    /* NOTE: We assume that iov countains at least <ret> bytes. */
639    while(ret > 0)
640    {
641        void *b = iov->iov_base;
642        size_t len = iov->iov_len;
643
644        if(len > (size_t)ret)
645            len = ret;
646
647        _zz_fuzz(fd, b, len);
648        _zz_addpos(fd, len);
649
650        iov++;
651        ret -= len;
652    }
653}
654#endif
655
656/* Sanity check, can be OK though (for instance with a character device) */
657static void offset_check(int fd)
658{
659    int orig_errno = errno;
660#if defined HAVE_LSEEK64
661    off64_t ret;
662    LOADSYM(lseek64);
663    ret = ORIG(lseek64)(fd, 0, SEEK_CUR);
664#else
665    off_t ret;
666    LOADSYM(lseek);
667    ret = ORIG(lseek)(fd, 0, SEEK_CUR);
668#endif
669    if(ret != -1 && ret != _zz_getpos(fd))
670        debug("warning: offset inconsistency");
671    errno = orig_errno;
672}
673
Note: See TracBrowser for help on using the repository browser.