source: zzuf/trunk/src/common/fuzz.c @ 4253

Last change on this file since 4253 was 4253, checked in by sam, 4 years ago

Fix copyright information and remove Id tag everywhere.

  • Property svn:keywords set to Id
File size: 6.0 KB
Line 
1/*
2 *  zzuf - general purpose fuzzer
3 *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
4 *                All Rights Reserved
5 *
6 *  This program is free software. It comes without any warranty, to
7 *  the extent permitted by applicable law. You can redistribute it
8 *  and/or modify it under the terms of the Do What The Fuck You Want
9 *  To Public License, Version 2, as published by Sam Hocevar. See
10 *  http://sam.zoy.org/wtfpl/COPYING for more details.
11 */
12
13/*
14 *  fuzz.c: fuzz functions
15 */
16
17#include "config.h"
18
19#if defined HAVE_STDINT_H
20#   include <stdint.h>
21#elif defined HAVE_INTTYPES_H
22#   include <inttypes.h>
23#endif
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include "common.h"
29#include "random.h"
30#include "fuzz.h"
31#include "fd.h"
32#include "ranges.h"
33#if defined LIBZZUF
34#   include "debug.h"
35#endif
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#if defined LIBZZUF
95    debug2("... fuzz(%i, @%lli, %lli)", fd, (long long int)pos,
96           (long long int)len);
97#endif
98
99    aligned_buf = buf - pos;
100    fuzz = _zz_getfuzz(fd);
101
102    for(i = pos / CHUNKBYTES;
103        i < (pos + len + CHUNKBYTES - 1) / CHUNKBYTES;
104        i++)
105    {
106        /* Cache bitmask array */
107        if(fuzz->cur != (int)i)
108        {
109            uint32_t chunkseed;
110
111            chunkseed = (uint32_t)i;
112            chunkseed ^= MAGIC2;
113            chunkseed += (uint32_t)(fuzz->ratio * MAGIC1);
114            chunkseed ^= fuzz->seed;
115            chunkseed += (uint32_t)(i * MAGIC3);
116
117            _zz_srand(chunkseed);
118
119            memset(fuzz->data, 0, CHUNKBYTES);
120
121            /* Add some random dithering to handle ratio < 1.0/CHUNKBYTES */
122            todo = (int)((fuzz->ratio * (8 * CHUNKBYTES) * 1000000.0
123                                + _zz_rand(1000000)) / 1000000.0);
124            while(todo--)
125            {
126                unsigned int idx = _zz_rand(CHUNKBYTES);
127                uint8_t bit = (1 << _zz_rand(8));
128
129                fuzz->data[idx] ^= bit;
130            }
131
132            fuzz->cur = i;
133        }
134
135        /* Apply our bitmask array to the buffer */
136        start = (i * CHUNKBYTES > pos) ? i * CHUNKBYTES : pos;
137
138        stop = ((i + 1) * CHUNKBYTES < pos + len)
139              ? (i + 1) * CHUNKBYTES : pos + len;
140
141        for(j = start; j < stop; j++)
142        {
143            uint8_t byte, fuzzbyte;
144
145            if(ranges && !_zz_isinrange(j, ranges))
146                continue; /* Not in one of the ranges, skip byte */
147
148            byte = aligned_buf[j];
149
150            if(protect[byte])
151                continue;
152
153            fuzzbyte = fuzz->data[j % CHUNKBYTES];
154
155            if(!fuzzbyte)
156                continue;
157
158            switch(fuzzing)
159            {
160            case FUZZING_XOR:
161                byte ^= fuzzbyte;
162                break;
163            case FUZZING_SET:
164                byte |= fuzzbyte;
165                break;
166            case FUZZING_UNSET:
167                byte &= ~fuzzbyte;
168                break;
169            }
170
171            if(refuse[byte])
172                continue;
173
174            aligned_buf[j] = byte;
175        }
176    }
177
178    /* Handle ungetc() */
179    if(fuzz->uflag)
180    {
181        fuzz->uflag = 0;
182        if(fuzz->upos == pos)
183            buf[0] = fuzz->uchar;
184    }
185}
186
187static void readchars(unsigned char *table, char const *list)
188{
189    static char const hex[] = "0123456789abcdef0123456789ABCDEF";
190    char const *tmp;
191    int a, b;
192
193    memset(table, 0, 256 * sizeof(unsigned char));
194
195    for(tmp = list, a = b = -1; *tmp; tmp++)
196    {
197        int new;
198
199        if(*tmp == '\\' && tmp[1] == '\0')
200            new = '\\';
201        else if(*tmp == '\\')
202        {
203            tmp++;
204            if(*tmp == 'n')
205                new = '\n';
206            else if(*tmp == 'r')
207                new = '\r';
208            else if(*tmp == 't')
209                new = '\t';
210            else if(tmp[0] >= '0' && tmp[0] <= '7' && tmp[1] >= '0'
211                     && tmp[1] <= '7' && tmp[2] >= '0' && tmp[2] <= '7')
212            {
213                new = tmp[2] - '0';
214                new |= (int)(tmp[1] - '0') << 3;
215                new |= (int)(tmp[0] - '0') << 6;
216                tmp += 2;
217            }
218            else if((*tmp == 'x' || *tmp == 'X')
219                     && tmp[1] && strchr(hex, tmp[1])
220                     && tmp[2] && strchr(hex, tmp[2]))
221            {
222                new = ((int)(strchr(hex, tmp[1]) - hex) & 0xf) << 4;
223                new |= (int)(strchr(hex, tmp[2]) - hex) & 0xf;
224                tmp += 2;
225            }
226            else
227                new = (unsigned char)*tmp; /* XXX: OK for \\, but what else? */
228        }
229        else
230            new = (unsigned char)*tmp;
231
232        if(a != -1 && b == '-' && a <= new)
233        {
234            while(a <= new)
235                table[a++] = 1;
236            a = b = -1;
237        }
238        else
239        {
240            if(a != -1)
241                table[a] = 1;
242            a = b;
243            b = new;
244        }
245    }
246
247    if(a != -1)
248        table[a] = 1;
249    if(b != -1)
250        table[b] = 1;
251}
252
Note: See TracBrowser for help on using the repository browser.