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