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

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

Improve the OpenSolaris? port: support for FILE structures, and a few
additional defines to activate libc features.

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