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