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

Last change on this file since 4262 was 4262, checked in by Sam Hocevar, 8 years ago

On HP-UX, connect(), bind() etc. do not use the struct sockaddr type but
use a void pointer instead. Check for that at configure time.

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