1 /* 	$OpenBSD: test_sshbuf_fuzz.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
2 /*
3  * Regress test for sshbuf.h buffer API
4  *
5  * Placed in the public domain
6  */
7 
8 #include <sys/types.h>
9 #include <sys/param.h>
10 #include <stdio.h>
11 #include <stdint.h>
12 #include <stdlib.h>
13 #include <string.h>
14 
15 #include "test_helper.h"
16 
17 #include "ssherr.h"
18 #include "sshbuf.h"
19 
20 #define NUM_FUZZ_TESTS (1 << 18)
21 
22 void sshbuf_fuzz_tests(void);
23 
24 void
25 sshbuf_fuzz_tests(void)
26 {
27 	struct sshbuf *p1;
28 	u_char *dp;
29 	size_t sz, sz2, i;
30 	u_int32_t r;
31 	int ret;
32 
33 	/* NB. uses sshbuf internals */
34 	TEST_START("fuzz alloc/dealloc");
35 	p1 = sshbuf_new();
36 	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 16 * 1024), 0);
37 	ASSERT_PTR_NE(p1, NULL);
38 	ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
39 	ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
40 	for (i = 0; i < NUM_FUZZ_TESTS; i++) {
41 		r = arc4random_uniform(10);
42 		if (r == 0) {
43 			/* 10% chance: small reserve */
44 			r = arc4random_uniform(10);
45  fuzz_reserve:
46 			sz = sshbuf_avail(p1);
47 			sz2 = sshbuf_len(p1);
48 			ret = sshbuf_reserve(p1, r, &dp);
49 			if (ret < 0) {
50 				ASSERT_PTR_EQ(dp, NULL);
51 				ASSERT_SIZE_T_LT(sz, r);
52 				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz);
53 				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2);
54 			} else {
55 				ASSERT_PTR_NE(dp, NULL);
56 				ASSERT_SIZE_T_GE(sz, r);
57 				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz - r);
58 				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2 + r);
59 				memset(dp, arc4random_uniform(255) + 1, r);
60 			}
61 		} else if (r < 3) {
62 			/* 20% chance: big reserve */
63 			r = arc4random_uniform(8 * 1024);
64 			goto fuzz_reserve;
65 		} else if (r == 3) {
66 			/* 10% chance: small consume */
67 			r = arc4random_uniform(10);
68  fuzz_consume:
69 			sz = sshbuf_avail(p1);
70 			sz2 = sshbuf_len(p1);
71 			/* 50% change consume from end, otherwise start */
72 			ret = ((arc4random() & 1) ?
73 			    sshbuf_consume : sshbuf_consume_end)(p1, r);
74 			if (ret < 0) {
75 				ASSERT_SIZE_T_LT(sz2, r);
76 				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz);
77 				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2);
78 			} else {
79 				ASSERT_SIZE_T_GE(sz2, r);
80 				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz + r);
81 				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2 - r);
82 			}
83 		} else if (r < 8) {
84 			/* 40% chance: big consume */
85 			r = arc4random_uniform(2 * 1024);
86 			goto fuzz_consume;
87 		} else if (r == 8) {
88 			/* 10% chance: reset max size */
89 			r = arc4random_uniform(16 * 1024);
90 			sz = sshbuf_max_size(p1);
91 			if (sshbuf_set_max_size(p1, r) < 0)
92 				ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), sz);
93 			else
94 				ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), r);
95 		} else {
96 			if (arc4random_uniform(8192) == 0) {
97 				/* tiny chance: new buffer */
98 				ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
99 				ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
100 				sshbuf_free(p1);
101 				p1 = sshbuf_new();
102 				ASSERT_PTR_NE(p1, NULL);
103 				ASSERT_INT_EQ(sshbuf_set_max_size(p1,
104 				    16 * 1024), 0);
105 			} else {
106 				/* Almost 10%: giant reserve */
107 				/* use arc4random_buf for r > 2^32 on 64 bit */
108 				arc4random_buf(&r, sizeof(r));
109 				while (r < SSHBUF_SIZE_MAX / 2) {
110 					r <<= 1;
111 					r |= arc4random() & 1;
112 				}
113 				goto fuzz_reserve;
114 			}
115 		}
116 		ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
117 		ASSERT_SIZE_T_LE(sshbuf_max_size(p1), 16 * 1024);
118 	}
119 	ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
120 	ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
121 	sshbuf_free(p1);
122 	TEST_DONE();
123 }
124