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

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