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

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