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

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