1/*
2 * Copyright (c) 2011 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Portions Copyright (c) 2011 - 2013 Apple Inc. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <sys/types.h>
37#include <inttypes.h>
38#include <roken.h>
39#define HEIM_FUZZER_INTERNALS 1
40#include "fuzzer.h"
41
42#define SIZE(_array) (sizeof(_array) / sizeof((_array)[0]))
43
44/*
45 *
46 */
47
48static void
49null_free(void *ctx)
50{
51    if (ctx != NULL)
52	abort();
53}
54
55/*
56 *
57 */
58
59#define MIN_RANDOM_TRIES 30000
60
61static unsigned long
62random_tries(size_t length)
63{
64    length = length * 12;
65    if (length < MIN_RANDOM_TRIES)
66	length = MIN_RANDOM_TRIES;
67    return (unsigned long)length;
68}
69
70static int
71random_fuzz(void **ctx, unsigned long iteration, uint8_t *data, size_t length)
72{
73    *ctx = NULL;
74
75    if (iteration > MIN_RANDOM_TRIES && iteration > length * 12)
76	return 1;
77
78    data[rk_random() % length] = rk_random();
79
80    return 0;
81}
82
83
84const struct heim_fuzz_type_data __heim_fuzz_random = {
85    "random",
86    random_tries,
87    random_fuzz,
88    null_free
89};
90
91/*
92 *
93 */
94
95static unsigned long
96bitflip_tries(size_t length)
97{
98    return length << 3;
99}
100
101static int
102bitflip_fuzz(void **ctx, unsigned long iteration, uint8_t *data, size_t length)
103{
104    *ctx = NULL;
105    if ((iteration >> 3) >= length)
106	return 1;
107    data[iteration >> 3] ^= (1 << (iteration & 7));
108
109    return 0;
110}
111
112const struct heim_fuzz_type_data __heim_fuzz_bitflip = {
113    "bitflip",
114    bitflip_tries,
115    bitflip_fuzz,
116    null_free
117};
118
119/*
120 *
121 */
122
123static unsigned long
124byteflip_tries(size_t length)
125{
126    return length;
127}
128
129static int
130byteflip_fuzz(void **ctx, unsigned long iteration, uint8_t *data, size_t length)
131{
132    *ctx = NULL;
133    if (iteration >= length)
134	return 1;
135    data[iteration] ^= 0xff;
136
137    return 0;
138}
139
140const struct heim_fuzz_type_data __heim_fuzz_byteflip = {
141    "byteflip",
142    byteflip_tries,
143    byteflip_fuzz,
144    null_free
145};
146
147/*
148 *
149 */
150
151static unsigned long
152shortflip_tries(size_t length)
153{
154    return length / 2;
155}
156
157static int
158shortflip_fuzz(void **ctx, unsigned long iteration, uint8_t *data, size_t length)
159{
160    *ctx = NULL;
161    if (iteration + 1 >= length / 2)
162	return 1;
163    data[iteration + 0] ^= 0xff;
164    data[iteration + 1] ^= 0xff;
165
166    return 0;
167}
168
169const struct heim_fuzz_type_data __heim_fuzz_shortflip = {
170    "shortflip",
171    shortflip_tries,
172    shortflip_fuzz,
173    null_free
174};
175
176/*
177 *
178 */
179
180static unsigned long
181wordflip_tries(size_t length)
182{
183    return length / 4;
184}
185
186static int
187wordflip_fuzz(void **ctx, unsigned long iteration, uint8_t *data, size_t length)
188{
189    if (ctx)
190	*ctx = NULL;
191    if (iteration + 3 >= length / 4)
192	return 1;
193    data[iteration + 0] ^= 0xff;
194    data[iteration + 1] ^= 0xff;
195    data[iteration + 2] ^= 0xff;
196    data[iteration + 3] ^= 0xff;
197
198    return 0;
199}
200
201const struct heim_fuzz_type_data __heim_fuzz_wordflip = {
202    "wordflip",
203    wordflip_tries,
204    wordflip_fuzz,
205    null_free
206};
207
208/*
209 * interesting values picked from AFL
210 */
211
212static uint8_t interesting_u8[] = {
213    -128,
214    -1,
215    0,
216    1,
217    16,
218    32,
219    64,
220    100,
221    127
222};
223
224static uint16_t interesting_u16[] = {
225    (uint16_t)-32768,
226    (uint16_t)-129,
227    128,
228    255,
229    256,
230    512,
231    1000,
232    1024,
233    4096,
234    32767
235};
236
237static uint32_t interesting_u32[] = {
238    (uint32_t)-2147483648LL,
239    (uint32_t)-100000000,
240    (uint32_t)-32769,
241    32768,
242   65535,
243   65536,
244   100000000,
245   2147483647
246};
247
248
249static unsigned long
250interesting_tries(size_t length)
251{
252    return length;
253}
254
255static int
256interesting8_fuzz(void **ctx, unsigned long iteration, uint8_t *data, size_t length)
257{
258    if (length < iteration / SIZE(interesting_u8))
259	return 1;
260
261    memcpy(&data[iteration % SIZE(interesting_u8)], &interesting_u8[iteration / SIZE(interesting_u8)], 1);
262    return 0;
263}
264
265const struct heim_fuzz_type_data __heim_fuzz_interesting8 = {
266    "interesting uint8",
267    interesting_tries,
268    interesting8_fuzz,
269    null_free
270};
271
272static int
273interesting16_fuzz(void **ctx, unsigned long iteration, uint8_t *data, size_t length)
274{
275    if (length < 1 + (iteration / SIZE(interesting_u16)))
276	return 1;
277
278    memcpy(&data[iteration % SIZE(interesting_u16)], &interesting_u16[iteration / SIZE(interesting_u16)], 2);
279    return 0;
280}
281
282const struct heim_fuzz_type_data __heim_fuzz_interesting16 = {
283    "interesting uint16",
284    interesting_tries,
285    interesting16_fuzz,
286    null_free
287};
288
289static int
290interesting32_fuzz(void **ctx, unsigned long iteration, uint8_t *data, size_t length)
291{
292    if (length < 3 + (iteration / SIZE(interesting_u32)))
293	return 1;
294
295    memcpy(&data[iteration % SIZE(interesting_u32)], &interesting_u32[iteration / SIZE(interesting_u32)], 4);
296    return 0;
297}
298
299const struct heim_fuzz_type_data __heim_fuzz_interesting32 = {
300    "interesting uint32",
301    interesting_tries,
302    interesting32_fuzz,
303    null_free
304};
305
306/*
307 *
308 */
309
310const char *
311heim_fuzzer_name(heim_fuzz_type_t type)
312{
313    return type->name;
314}
315
316unsigned long
317heim_fuzzer_tries(heim_fuzz_type_t type, size_t length)
318{
319    return type->tries(length);
320}
321
322int
323heim_fuzzer(heim_fuzz_type_t type,
324	    void **ctx,
325	    unsigned long iteration,
326	    uint8_t *data,
327	    size_t length)
328{
329    if (length == 0)
330	return 1;
331    return type->fuzz(ctx, iteration, data, length);
332}
333
334void
335heim_fuzzer_free(heim_fuzz_type_t type,
336		 void *ctx)
337{
338    if (ctx != NULL)
339	type->freectx(ctx);
340}
341