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

Last change on this file since 1863 was 1863, checked in by Sam Hocevar, 13 years ago
  • Merged the bind() and connect() diversions using macros. They were almost identical.
  • Check the addrlen value to avoid crashing with weird protocols.
  • Property svn:keywords set to Id
File size: 14.8 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 1863 2007-11-02 23:34:22Z 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 AF_INET6
197#   define case_AF_INET6 case AF_INET6:
198#else
199#   define case_AF_INET6
200#endif
201
202#define CONNECTION(fn, addr) \
203    do \
204    { \
205        LOADSYM(fn); \
206        ret = ORIG(fn)(sockfd, addr, addrlen); \
207        if(!_zz_ready || _zz_islocked(-1) || !_zz_network) \
208            return ret; \
209        if(ret >= 0) \
210        { \
211            const struct sockaddr_in* in = (const struct sockaddr_in *)addr; \
212            long int port; \
213            switch(addr->sa_family) \
214            { \
215            case AF_UNSPEC: \
216                if(addrlen < sizeof(struct sockaddr_in)) \
217                    break; \
218                /* Fall through */ \
219            case AF_INET: \
220            case_AF_INET6 \
221                port = ntohs(in->sin_port); \
222                if(!_zz_portwatched(port)) \
223                { \
224                    _zz_unregister(sockfd); \
225                    return ret; \
226                } \
227                break; \
228            default: \
229                break; \
230            } \
231            debug("%s(%i, %p, %i) = %i", __func__, \
232                  sockfd, addr, (int)addrlen, ret); \
233        } \
234    } while(0);
235
236#if defined HAVE_BIND
237int NEW(bind)(int sockfd, const struct sockaddr *my_addr, SOCKLEN_T addrlen)
238{
239    int ret; CONNECTION(bind, my_addr); return ret;
240}
241#endif
242
243#if defined HAVE_CONNECT
244int NEW(connect)(int sockfd, const struct sockaddr *serv_addr,
245                 SOCKLEN_T addrlen)
246{
247    int ret; CONNECTION(connect, serv_addr); return ret;
248}
249#endif
250
251#if defined HAVE_SOCKET
252int NEW(socket)(int domain, int type, int protocol)
253{
254    int ret;
255
256    LOADSYM(socket);
257    ret = ORIG(socket)(domain, type, protocol);
258    if(!_zz_ready || _zz_islocked(-1) || !_zz_network)
259        return ret;
260
261    if(ret >= 0)
262    {
263        debug("%s(%i, %i, %i) = %i", __func__, domain, type, protocol, ret);
264        _zz_register(ret);
265    }
266
267    return ret;
268}
269#endif
270
271#if defined HAVE_RECV
272RECV_T NEW(recv)(int s, void *buf, size_t len, int flags)
273{
274    int ret;
275
276    LOADSYM(recv);
277    ret = ORIG(recv)(s, buf, len, flags);
278    if(!_zz_ready || !_zz_iswatched(s) || _zz_islocked(s) || !_zz_isactive(s))
279        return ret;
280
281    if(ret > 0)
282    {
283        char *b = buf;
284
285        _zz_fuzz(s, buf, ret);
286        _zz_addpos(s, ret);
287
288        if(ret >= 4)
289            debug("%s(%i, %p, %li, 0x%x) = %i \"%c%c%c%c...", __func__,
290                  s, buf, (long int)len, flags, ret, b[0], b[1], b[2], b[3]);
291        else
292            debug("%s(%i, %p, %li, 0x%x) = %i \"%c...", __func__,
293                  s, buf, (long int)len, flags, ret, b[0]);
294    }
295    else
296        debug("%s(%i, %p, %li, 0x%x) = %i", __func__,
297              s, buf, (long int)len, flags, ret);
298
299    return ret;
300}
301#endif
302
303#if defined HAVE_RECVFROM
304RECV_T NEW(recvfrom)(int s, void *buf, size_t len, int flags,
305                     struct sockaddr *from, SOCKLEN_T *fromlen)
306{
307    int ret;
308
309    LOADSYM(recvfrom);
310    ret = ORIG(recvfrom)(s, buf, len, flags, from, fromlen);
311    if(!_zz_ready || !_zz_iswatched(s) || _zz_islocked(s) || !_zz_isactive(s))
312        return ret;
313
314    if(ret > 0)
315    {
316        char *b = buf;
317
318        _zz_fuzz(s, buf, ret);
319        _zz_addpos(s, ret);
320
321        if(ret >= 4)
322            debug("%s(%i, %p, %li, 0x%x, %p, &%i) = %i \"%c%c%c%c...",
323                  __func__, s, buf, (long int)len, flags, from, (int)*fromlen,
324                  ret, b[0], b[1], b[2], b[3]);
325        else
326            debug("%s(%i, %p, %li, 0x%x, %p, &%i) = %i \"%c...",
327                  __func__, s, buf, (long int)len, flags, from, (int)*fromlen,
328                  ret, b[0]);
329    }
330    else
331        debug("%s(%i, %p, %li, 0x%x, %p, %p) = %i", __func__,
332              s, buf, (long int)len, flags, from, fromlen, ret);
333
334    return ret;
335}
336#endif
337
338#if defined HAVE_RECVMSG
339RECV_T NEW(recvmsg)(int s, struct msghdr *hdr, int flags)
340{
341    ssize_t ret;
342
343    LOADSYM(recvmsg);
344    ret = ORIG(recvmsg)(s, hdr, flags);
345    if(!_zz_ready || !_zz_iswatched(s) || _zz_islocked(s) || !_zz_isactive(s))
346        return ret;
347
348    fuzz_iovec(s, hdr->msg_iov, ret);
349    debug("%s(%i, %p, %x) = %li", __func__, s, hdr, flags, (long int)ret);
350
351    return ret;
352}
353#endif
354
355#if defined READ_USES_SSIZE_T
356ssize_t NEW(read)(int fd, void *buf, size_t count)
357#else
358int NEW(read)(int fd, void *buf, unsigned int count)
359#endif
360{
361    int ret;
362
363    LOADSYM(read);
364    ret = ORIG(read)(fd, buf, count);
365    if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd)
366         || !_zz_isactive(fd))
367        return ret;
368
369    if(ret > 0)
370    {
371        char *b = buf;
372
373        _zz_fuzz(fd, buf, ret);
374        _zz_addpos(fd, ret);
375
376        if(ret >= 4)
377            debug("%s(%i, %p, %li) = %i \"%c%c%c%c...", __func__, fd, buf,
378                  (long int)count, ret, b[0], b[1], b[2], b[3]);
379        else
380            debug("%s(%i, %p, %li) = %i \"%c...", __func__, fd, buf,
381                  (long int)count, ret, b[0]);
382    }
383    else
384        debug("%s(%i, %p, %li) = %i", __func__, fd, buf, (long int)count, ret);
385
386    offset_check(fd);
387    return ret;
388}
389
390#if defined HAVE_READV
391ssize_t NEW(readv)(int fd, const struct iovec *iov, int count)
392{
393    ssize_t ret;
394
395    LOADSYM(readv);
396    ret = ORIG(readv)(fd, iov, count);
397    if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd)
398         || !_zz_isactive(fd))
399        return ret;
400
401    fuzz_iovec(fd, iov, ret);
402    debug("%s(%i, %p, %i) = %li", __func__, fd, iov, count, (long int)ret);
403
404    offset_check(fd);
405    return ret;
406}
407#endif
408
409#if defined HAVE_PREAD
410ssize_t NEW(pread)(int fd, void *buf, size_t count, off_t offset)
411{
412    int ret;
413
414    LOADSYM(pread);
415    ret = ORIG(pread)(fd, buf, count, offset);
416    if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd)
417         || !_zz_isactive(fd))
418        return ret;
419
420    if(ret > 0)
421    {
422        long int curoff = _zz_getpos(fd);
423        char *b = buf;
424
425        _zz_setpos(fd, offset);
426        _zz_fuzz(fd, buf, ret);
427        _zz_setpos(fd, curoff);
428
429        if(ret >= 4)
430            debug("%s(%i, %p, %li, %li) = %i \"%c%c%c%c...", __func__, fd, buf,
431                  (long int)count, (long int)offset, ret,
432                  b[0], b[1], b[2], b[3]);
433        else
434            debug("%s(%i, %p, %li, %li) = %i \"%c...", __func__, fd, buf,
435                  (long int)count, (long int)offset, ret, b[0]);
436    }
437    else
438        debug("%s(%i, %p, %li, %li) = %i", __func__, fd, buf,
439              (long int)count, (long int)offset, ret);
440
441    return ret;
442}
443#endif
444
445#define LSEEK(fn, off_t) \
446    do \
447    { \
448        LOADSYM(fn); \
449        ret = ORIG(fn)(fd, offset, whence); \
450        if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd) \
451             || !_zz_isactive(fd)) \
452            return ret; \
453        debug("%s(%i, %lli, %i) = %lli", __func__, fd, \
454              (long long int)offset, whence, (long long int)ret); \
455        if(ret != (off_t)-1) \
456            _zz_setpos(fd, ret); \
457    } while(0)
458
459off_t NEW(lseek)(int fd, off_t offset, int whence)
460{
461    off_t ret;
462    LSEEK(lseek, off_t);
463    return ret;
464}
465
466#if defined HAVE_LSEEK64
467off64_t NEW(lseek64)(int fd, off64_t offset, int whence)
468{
469    off64_t ret;
470    LSEEK(lseek64, off64_t);
471    return ret;
472}
473#endif
474
475#if defined HAVE_AIO_READ
476int NEW(aio_read)(struct aiocb *aiocbp)
477{
478    int ret;
479    int fd = aiocbp->aio_fildes;
480
481    LOADSYM(aio_read);
482    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
483        return ORIG(aio_read)(aiocbp);
484
485    _zz_lock(fd);
486    ret = ORIG(aio_read)(aiocbp);
487
488    debug("%s({%i, %i, %i, %p, %li, ..., %li}) = %i", __func__,
489          fd, aiocbp->aio_lio_opcode, aiocbp->aio_reqprio, aiocbp->aio_buf,
490          (long int)aiocbp->aio_nbytes, (long int)aiocbp->aio_offset, ret);
491
492    return ret;
493}
494
495ssize_t NEW(aio_return)(struct aiocb *aiocbp)
496{
497    ssize_t ret;
498    int fd = aiocbp->aio_fildes;
499
500    LOADSYM(aio_return);
501    if(!_zz_ready || !_zz_iswatched(fd) || !_zz_isactive(fd))
502        return ORIG(aio_return)(aiocbp);
503
504    ret = ORIG(aio_return)(aiocbp);
505    _zz_unlock(fd);
506
507    /* FIXME: make sure we’re actually *reading* */
508    if(ret > 0)
509    {
510        _zz_setpos(fd, aiocbp->aio_offset);
511        _zz_fuzz(fd, aiocbp->aio_buf, ret);
512        _zz_addpos(fd, ret);
513    }
514
515    debug("%s({%i, %i, %i, %p, %li, ..., %li}) = %li", __func__,
516          fd, aiocbp->aio_lio_opcode, aiocbp->aio_reqprio, aiocbp->aio_buf,
517          (long int)aiocbp->aio_nbytes, (long int)aiocbp->aio_offset,
518          (long int)ret);
519
520    return ret;
521}
522#endif
523
524int NEW(close)(int fd)
525{
526    int ret;
527
528    /* Hey, it’s our debug channel! Silently pretend we closed it. */
529    if(fd == _zz_debugfd)
530        return 0;
531
532    LOADSYM(close);
533    ret = ORIG(close)(fd);
534    if(!_zz_ready || !_zz_iswatched(fd) || _zz_islocked(fd))
535        return ret;
536
537    debug("%s(%i) = %i", __func__, fd, ret);
538    _zz_unregister(fd);
539
540    return ret;
541}
542
543/* XXX: the following functions are local */
544
545#if defined HAVE_READV || defined HAVE_RECVMSG
546static void fuzz_iovec(int fd, const struct iovec *iov, ssize_t ret)
547{
548    /* NOTE: We assume that iov countains at least <ret> bytes. */
549    while(ret > 0)
550    {
551        void *b = iov->iov_base;
552        size_t len = iov->iov_len;
553
554        if(len > (size_t)ret)
555            len = ret;
556
557        _zz_fuzz(fd, b, len);
558        _zz_addpos(fd, len);
559
560        iov++;
561        ret -= len;
562    }
563}
564#endif
565
566/* Sanity check, can be OK though (for instance with a character device) */
567static void offset_check(int fd)
568{
569    int orig_errno = errno;
570#if defined HAVE_LSEEK64
571    off64_t ret;
572    LOADSYM(lseek64);
573    ret = ORIG(lseek64)(fd, 0, SEEK_CUR);
574#else
575    off_t ret;
576    LOADSYM(lseek);
577    ret = ORIG(lseek)(fd, 0, SEEK_CUR);
578#endif
579    if(ret != -1 && ret != _zz_getpos(fd))
580        debug("warning: offset inconsistency");
581    errno = orig_errno;
582}
583
Note: See TracBrowser for help on using the repository browser.