xref: /openbsd-src/regress/usr.bin/ssh/unittests/sshbuf/test_sshbuf_fuzz.c (revision 1f91717ebfc73b1781d1076ffda42aa88be98504)
1*1f91717eSanton /* 	$OpenBSD: test_sshbuf_fuzz.c,v 1.4 2021/12/18 06:53:59 anton Exp $ */
229518ea0Sdjm /*
329518ea0Sdjm  * Regress test for sshbuf.h buffer API
429518ea0Sdjm  *
529518ea0Sdjm  * Placed in the public domain
629518ea0Sdjm  */
729518ea0Sdjm 
829518ea0Sdjm #include <sys/types.h>
929518ea0Sdjm #include <stdio.h>
1029518ea0Sdjm #include <stdint.h>
1129518ea0Sdjm #include <stdlib.h>
1229518ea0Sdjm #include <string.h>
1329518ea0Sdjm 
1429518ea0Sdjm #include "test_helper.h"
1529518ea0Sdjm 
1629518ea0Sdjm #include "ssherr.h"
1729518ea0Sdjm #include "sshbuf.h"
1829518ea0Sdjm 
1929518ea0Sdjm #define NUM_FUZZ_TESTS (1 << 18)
2029518ea0Sdjm 
2129518ea0Sdjm void sshbuf_fuzz_tests(void);
2229518ea0Sdjm 
2329518ea0Sdjm void
sshbuf_fuzz_tests(void)2429518ea0Sdjm sshbuf_fuzz_tests(void)
2529518ea0Sdjm {
2629518ea0Sdjm 	struct sshbuf *p1;
2729518ea0Sdjm 	u_char *dp;
28a76a1e99Sdjm 	size_t sz, sz2, i, ntests = NUM_FUZZ_TESTS;
2929518ea0Sdjm 	u_int32_t r;
3029518ea0Sdjm 	int ret;
3129518ea0Sdjm 
32a76a1e99Sdjm 	if (test_is_fast())
33a76a1e99Sdjm 		ntests >>= 2;
34a76a1e99Sdjm 	if (test_is_slow())
35a76a1e99Sdjm 		ntests <<= 2;
36a76a1e99Sdjm 
3729518ea0Sdjm 	/* NB. uses sshbuf internals */
3829518ea0Sdjm 	TEST_START("fuzz alloc/dealloc");
3929518ea0Sdjm 	p1 = sshbuf_new();
4029518ea0Sdjm 	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 16 * 1024), 0);
4129518ea0Sdjm 	ASSERT_PTR_NE(p1, NULL);
4229518ea0Sdjm 	ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
4329518ea0Sdjm 	ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
44*1f91717eSanton 	for (i = 0; i < ntests; i++) {
4529518ea0Sdjm 		r = arc4random_uniform(10);
4629518ea0Sdjm 		if (r == 0) {
4729518ea0Sdjm 			/* 10% chance: small reserve */
4829518ea0Sdjm 			r = arc4random_uniform(10);
4929518ea0Sdjm  fuzz_reserve:
5029518ea0Sdjm 			sz = sshbuf_avail(p1);
5129518ea0Sdjm 			sz2 = sshbuf_len(p1);
5229518ea0Sdjm 			ret = sshbuf_reserve(p1, r, &dp);
5329518ea0Sdjm 			if (ret < 0) {
5429518ea0Sdjm 				ASSERT_PTR_EQ(dp, NULL);
5529518ea0Sdjm 				ASSERT_SIZE_T_LT(sz, r);
5629518ea0Sdjm 				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz);
5729518ea0Sdjm 				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2);
5829518ea0Sdjm 			} else {
5929518ea0Sdjm 				ASSERT_PTR_NE(dp, NULL);
6029518ea0Sdjm 				ASSERT_SIZE_T_GE(sz, r);
6129518ea0Sdjm 				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz - r);
6229518ea0Sdjm 				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2 + r);
6329518ea0Sdjm 				memset(dp, arc4random_uniform(255) + 1, r);
6429518ea0Sdjm 			}
6529518ea0Sdjm 		} else if (r < 3) {
6629518ea0Sdjm 			/* 20% chance: big reserve */
6729518ea0Sdjm 			r = arc4random_uniform(8 * 1024);
6829518ea0Sdjm 			goto fuzz_reserve;
6929518ea0Sdjm 		} else if (r == 3) {
7029518ea0Sdjm 			/* 10% chance: small consume */
7129518ea0Sdjm 			r = arc4random_uniform(10);
7229518ea0Sdjm  fuzz_consume:
7329518ea0Sdjm 			sz = sshbuf_avail(p1);
7429518ea0Sdjm 			sz2 = sshbuf_len(p1);
7529518ea0Sdjm 			/* 50% change consume from end, otherwise start */
7629518ea0Sdjm 			ret = ((arc4random() & 1) ?
7729518ea0Sdjm 			    sshbuf_consume : sshbuf_consume_end)(p1, r);
7829518ea0Sdjm 			if (ret < 0) {
7929518ea0Sdjm 				ASSERT_SIZE_T_LT(sz2, r);
8029518ea0Sdjm 				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz);
8129518ea0Sdjm 				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2);
8229518ea0Sdjm 			} else {
8329518ea0Sdjm 				ASSERT_SIZE_T_GE(sz2, r);
8429518ea0Sdjm 				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz + r);
8529518ea0Sdjm 				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2 - r);
8629518ea0Sdjm 			}
8729518ea0Sdjm 		} else if (r < 8) {
8829518ea0Sdjm 			/* 40% chance: big consume */
8929518ea0Sdjm 			r = arc4random_uniform(2 * 1024);
9029518ea0Sdjm 			goto fuzz_consume;
9129518ea0Sdjm 		} else if (r == 8) {
9229518ea0Sdjm 			/* 10% chance: reset max size */
9329518ea0Sdjm 			r = arc4random_uniform(16 * 1024);
9429518ea0Sdjm 			sz = sshbuf_max_size(p1);
9529518ea0Sdjm 			if (sshbuf_set_max_size(p1, r) < 0)
9629518ea0Sdjm 				ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), sz);
9729518ea0Sdjm 			else
9829518ea0Sdjm 				ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), r);
9929518ea0Sdjm 		} else {
10029518ea0Sdjm 			if (arc4random_uniform(8192) == 0) {
10129518ea0Sdjm 				/* tiny chance: new buffer */
10229518ea0Sdjm 				ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
10329518ea0Sdjm 				ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
10429518ea0Sdjm 				sshbuf_free(p1);
10529518ea0Sdjm 				p1 = sshbuf_new();
10629518ea0Sdjm 				ASSERT_PTR_NE(p1, NULL);
10729518ea0Sdjm 				ASSERT_INT_EQ(sshbuf_set_max_size(p1,
10829518ea0Sdjm 				    16 * 1024), 0);
10929518ea0Sdjm 			} else {
11029518ea0Sdjm 				/* Almost 10%: giant reserve */
11129518ea0Sdjm 				/* use arc4random_buf for r > 2^32 on 64 bit */
11229518ea0Sdjm 				arc4random_buf(&r, sizeof(r));
11329518ea0Sdjm 				while (r < SSHBUF_SIZE_MAX / 2) {
11429518ea0Sdjm 					r <<= 1;
11529518ea0Sdjm 					r |= arc4random() & 1;
11629518ea0Sdjm 				}
11729518ea0Sdjm 				goto fuzz_reserve;
11829518ea0Sdjm 			}
11929518ea0Sdjm 		}
12029518ea0Sdjm 		ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
12129518ea0Sdjm 		ASSERT_SIZE_T_LE(sshbuf_max_size(p1), 16 * 1024);
12229518ea0Sdjm 	}
12329518ea0Sdjm 	ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
12429518ea0Sdjm 	ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
12529518ea0Sdjm 	sshbuf_free(p1);
12629518ea0Sdjm 	TEST_DONE();
12729518ea0Sdjm }
128