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

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