132785Speter/* 	$OpenBSD: test_sshbuf_fuzz.c,v 1.4 2021/12/18 06:53:59 anton Exp $ */
232785Speter/*
332785Speter * Regress test for sshbuf.h buffer API
432785Speter *
532785Speter * Placed in the public domain
632785Speter */
732785Speter
832785Speter#include "includes.h"
932785Speter
1032785Speter#include <sys/types.h>
1132785Speter#include <stdio.h>
1232785Speter#ifdef HAVE_STDINT_H
1332785Speter# include <stdint.h>
1432785Speter#endif
1532785Speter#include <stdlib.h>
1632785Speter#include <string.h>
1732785Speter
1832785Speter#include "../test_helper/test_helper.h"
1932785Speter
2032785Speter#include "ssherr.h"
2132785Speter#include "sshbuf.h"
2232785Speter
2332785Speter#define NUM_FUZZ_TESTS (1 << 18)
2432785Speter
2532785Spetervoid sshbuf_fuzz_tests(void);
2632785Speter
2732785Spetervoid
2832785Spetersshbuf_fuzz_tests(void)
2932785Speter{
3032785Speter	struct sshbuf *p1;
3132785Speter	u_char *dp;
3232785Speter	size_t sz, sz2, i, ntests = NUM_FUZZ_TESTS;
3332785Speter	u_int32_t r;
3432785Speter	int ret;
3532785Speter
3632785Speter	if (test_is_fast())
3732785Speter		ntests >>= 2;
3832785Speter	if (test_is_slow())
3932785Speter		ntests <<= 2;
4032785Speter
4132785Speter	/* NB. uses sshbuf internals */
4232785Speter	TEST_START("fuzz alloc/dealloc");
4332785Speter	p1 = sshbuf_new();
4432785Speter	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 16 * 1024), 0);
4532785Speter	ASSERT_PTR_NE(p1, NULL);
4632785Speter	ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
4732785Speter	ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
4832785Speter	for (i = 0; i < ntests; i++) {
4932785Speter		r = arc4random_uniform(10);
5032785Speter		if (r == 0) {
5132785Speter			/* 10% chance: small reserve */
5232785Speter			r = arc4random_uniform(10);
5332785Speter fuzz_reserve:
5432785Speter			sz = sshbuf_avail(p1);
5532785Speter			sz2 = sshbuf_len(p1);
5632785Speter			ret = sshbuf_reserve(p1, r, &dp);
5732785Speter			if (ret < 0) {
5832785Speter				ASSERT_PTR_EQ(dp, NULL);
5932785Speter				ASSERT_SIZE_T_LT(sz, r);
6032785Speter				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz);
6132785Speter				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2);
6232785Speter			} else {
6332785Speter				ASSERT_PTR_NE(dp, NULL);
6432785Speter				ASSERT_SIZE_T_GE(sz, r);
6532785Speter				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz - r);
6632785Speter				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2 + r);
6732785Speter				memset(dp, arc4random_uniform(255) + 1, r);
6832785Speter			}
6932785Speter		} else if (r < 3) {
7032785Speter			/* 20% chance: big reserve */
7132785Speter			r = arc4random_uniform(8 * 1024);
7232785Speter			goto fuzz_reserve;
7332785Speter		} else if (r == 3) {
7432785Speter			/* 10% chance: small consume */
7532785Speter			r = arc4random_uniform(10);
7632785Speter fuzz_consume:
7732785Speter			sz = sshbuf_avail(p1);
7832785Speter			sz2 = sshbuf_len(p1);
7932785Speter			/* 50% change consume from end, otherwise start */
8032785Speter			ret = ((arc4random() & 1) ?
8132785Speter			    sshbuf_consume : sshbuf_consume_end)(p1, r);
8232785Speter			if (ret < 0) {
8332785Speter				ASSERT_SIZE_T_LT(sz2, r);
8432785Speter				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz);
8532785Speter				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2);
8632785Speter			} else {
8732785Speter				ASSERT_SIZE_T_GE(sz2, r);
8832785Speter				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz + r);
8932785Speter				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2 - r);
9032785Speter			}
9132785Speter		} else if (r < 8) {
9232785Speter			/* 40% chance: big consume */
9332785Speter			r = arc4random_uniform(2 * 1024);
9432785Speter			goto fuzz_consume;
9532785Speter		} else if (r == 8) {
9632785Speter			/* 10% chance: reset max size */
9732785Speter			r = arc4random_uniform(16 * 1024);
9832785Speter			sz = sshbuf_max_size(p1);
9932785Speter			if (sshbuf_set_max_size(p1, r) < 0)
10032785Speter				ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), sz);
10132785Speter			else
10232785Speter				ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), r);
10332785Speter		} else {
10432785Speter			if (arc4random_uniform(8192) == 0) {
10532785Speter				/* tiny chance: new buffer */
10632785Speter				ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
10732785Speter				ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
10832785Speter				sshbuf_free(p1);
10932785Speter				p1 = sshbuf_new();
11032785Speter				ASSERT_PTR_NE(p1, NULL);
11132785Speter				ASSERT_INT_EQ(sshbuf_set_max_size(p1,
11232785Speter				    16 * 1024), 0);
11332785Speter			} else {
11432785Speter				/* Almost 10%: giant reserve */
11532785Speter				/* use arc4random_buf for r > 2^32 on 64 bit */
11632785Speter				arc4random_buf(&r, sizeof(r));
11732785Speter				while (r < SSHBUF_SIZE_MAX / 2) {
11832785Speter					r <<= 1;
11932785Speter					r |= arc4random() & 1;
12032785Speter				}
12132785Speter				goto fuzz_reserve;
12232785Speter			}
12332785Speter		}
12432785Speter		ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
12532785Speter		ASSERT_SIZE_T_LE(sshbuf_max_size(p1), 16 * 1024);
12632785Speter	}
12732785Speter	ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
12832785Speter	ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
12932785Speter	sshbuf_free(p1);
13032785Speter	TEST_DONE();
13132785Speter}
13232785Speter