source: zzuf/trunk/src/fuzz.c @ 2575

Last change on this file since 2575 was 2575, checked in by Sam Hocevar, 12 years ago
  • fuzz.c: activate the fuzz() debug message, it may be verbose but I end up activating it all the time anyway.
  • Property svn:keywords set to Id
File size: 6.0 KB
Line 
1/*
2 *  zzuf - general purpose fuzzer
3 *  Copyright (c) 2006-2007 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: fuzz.c 2575 2008-07-20 10:10:35Z sam $
7 *
8 *  This program is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15/*
16 *  fuzz.c: fuzz functions
17 */
18
19#include "config.h"
20
21#if defined HAVE_STDINT_H
22#   include <stdint.h>
23#elif defined HAVE_INTTYPES_H
24#   include <inttypes.h>
25#endif
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29
30#include "libzzuf.h"
31#include "debug.h"
32#include "random.h"
33#include "fuzz.h"
34#include "fd.h"
35#include "ranges.h"
36
37#define MAGIC1 0x33ea84f7
38#define MAGIC2 0x783bc31f
39#define MAGIC3 0x9b5da2fb
40
41/* Fuzzing mode */
42static enum fuzzing
43{
44    FUZZING_XOR = 0, FUZZING_SET, FUZZING_UNSET
45}
46fuzzing;
47
48/* Per-offset byte protection */
49static int *ranges = NULL;
50static int static_ranges[512];
51
52/* Per-value byte protection */
53static unsigned char protect[256];
54static unsigned char refuse[256];
55
56/* Local prototypes */
57static void readchars(unsigned char *, char const *);
58
59extern void _zz_fuzzing(char const *mode)
60{
61    if(!strcmp(mode, "xor"))
62        fuzzing = FUZZING_XOR;
63    else if(!strcmp(mode, "set"))
64        fuzzing = FUZZING_SET;
65    else if(!strcmp(mode, "unset"))
66        fuzzing = FUZZING_UNSET;
67}
68
69void _zz_bytes(char const *list)
70{
71    /* TODO: free(ranges) if ranges != static_ranges */
72    ranges = _zz_allocrange(list, static_ranges);
73}
74
75void _zz_protect(char const *list)
76{
77    readchars(protect, list);
78}
79
80void _zz_refuse(char const *list)
81{
82    readchars(refuse, list);
83}
84
85void _zz_fuzz(int fd, volatile uint8_t *buf, int64_t len)
86{
87    int64_t start, stop;
88    int64_t pos = _zz_getpos(fd);
89    struct fuzz *fuzz;
90    volatile uint8_t *aligned_buf;
91    int64_t i, j;
92    int todo;
93
94    debug("fuzz(%i, @%lli, %lli)", fd, (long long int)pos, (long long int)len);
95
96    aligned_buf = buf - pos;
97    fuzz = _zz_getfuzz(fd);
98
99    for(i = pos / CHUNKBYTES;
100        i < (pos + len + CHUNKBYTES - 1) / CHUNKBYTES;
101        i++)
102    {
103        /* Cache bitmask array */
104        if(fuzz->cur != (int)i)
105        {
106            uint32_t chunkseed;
107
108            chunkseed = (uint32_t)i;
109            chunkseed ^= MAGIC2;
110            chunkseed += (uint32_t)(fuzz->ratio * MAGIC1);
111            chunkseed ^= fuzz->seed;
112            chunkseed += (uint32_t)(i * MAGIC3);
113
114            _zz_srand(chunkseed);
115
116            memset(fuzz->data, 0, CHUNKBYTES);
117
118            /* Add some random dithering to handle ratio < 1.0/CHUNKBYTES */
119            todo = (int)((fuzz->ratio * (8 * CHUNKBYTES) * 1000000.0
120                                + _zz_rand(1000000)) / 1000000.0);
121            while(todo--)
122            {
123                unsigned int idx = _zz_rand(CHUNKBYTES);
124                uint8_t bit = (1 << _zz_rand(8));
125
126                fuzz->data[idx] ^= bit;
127            }
128
129            fuzz->cur = i;
130        }
131
132        /* Apply our bitmask array to the buffer */
133        start = (i * CHUNKBYTES > pos) ? i * CHUNKBYTES : pos;
134
135        stop = ((i + 1) * CHUNKBYTES < pos + len)
136              ? (i + 1) * CHUNKBYTES : pos + len;
137
138        for(j = start; j < stop; j++)
139        {
140            uint8_t byte, fuzzbyte;
141
142            if(ranges && !_zz_isinrange(j, ranges))
143                continue; /* Not in one of the ranges, skip byte */
144
145            byte = aligned_buf[j];
146
147            if(protect[byte])
148                continue;
149
150            fuzzbyte = fuzz->data[j % CHUNKBYTES];
151
152            if(!fuzzbyte)
153                continue;
154
155            switch(fuzzing)
156            {
157            case FUZZING_XOR:
158                byte ^= fuzzbyte;
159                break;
160            case FUZZING_SET:
161                byte |= fuzzbyte;
162                break;
163            case FUZZING_UNSET:
164                byte &= ~fuzzbyte;
165                break;
166            }
167
168            if(refuse[byte])
169                continue;
170
171            aligned_buf[j] = byte;
172        }
173    }
174
175    /* Handle ungetc() */
176    if(fuzz->uflag)
177    {
178        fuzz->uflag = 0;
179        if(fuzz->upos == pos)
180            buf[0] = fuzz->uchar;
181    }
182}
183
184static void readchars(unsigned char *table, char const *list)
185{
186    static char const hex[] = "0123456789abcdef0123456789ABCDEF";
187    char const *tmp;
188    int a, b;
189
190    memset(table, 0, 256 * sizeof(unsigned char));
191
192    for(tmp = list, a = b = -1; *tmp; tmp++)
193    {
194        int new;
195
196        if(*tmp == '\\' && tmp[1] == '\0')
197            new = '\\';
198        else if(*tmp == '\\')
199        {
200            tmp++;
201            if(*tmp == 'n')
202                new = '\n';
203            else if(*tmp == 'r')
204                new = '\r';
205            else if(*tmp == 't')
206                new = '\t';
207            else if(tmp[0] >= '0' && tmp[0] <= '7' && tmp[1] >= '0'
208                     && tmp[1] <= '7' && tmp[2] >= '0' && tmp[2] <= '7')
209            {
210                new = tmp[2] - '0';
211                new |= (int)(tmp[1] - '0') << 3;
212                new |= (int)(tmp[0] - '0') << 6;
213                tmp += 2;
214            }
215            else if((*tmp == 'x' || *tmp == 'X')
216                     && tmp[1] && strchr(hex, tmp[1])
217                     && tmp[2] && strchr(hex, tmp[2]))
218            {
219                new = ((int)(strchr(hex, tmp[1]) - hex) & 0xf) << 4;
220                new |= (int)(strchr(hex, tmp[2]) - hex) & 0xf;
221                tmp += 2;
222            }
223            else
224                new = (unsigned char)*tmp; /* XXX: OK for \\, but what else? */
225        }
226        else
227            new = (unsigned char)*tmp;
228
229        if(a != -1 && b == '-' && a <= new)
230        {
231            while(a <= new)
232                table[a++] = 1;
233            a = b = -1;
234        }
235        else
236        {
237            if(a != -1)
238                table[a] = 1;
239            a = b;
240            b = new;
241        }
242    }
243
244    if(a != -1)
245        table[a] = 1;
246    if(b != -1)
247        table[b] = 1;
248}
249
Note: See TracBrowser for help on using the repository browser.