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

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