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