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

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