1276707Sdes/* 	$OpenBSD: test_sshbuf_fuzz.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
2276707Sdes/*
3276707Sdes * Regress test for sshbuf.h buffer API
4276707Sdes *
5276707Sdes * Placed in the public domain
6276707Sdes */
7276707Sdes
8276707Sdes#include "includes.h"
9276707Sdes
10276707Sdes#include <sys/types.h>
11276707Sdes#include <sys/param.h>
12276707Sdes#include <stdio.h>
13276707Sdes#ifdef HAVE_STDINT_H
14276707Sdes# include <stdint.h>
15276707Sdes#endif
16276707Sdes#include <stdlib.h>
17276707Sdes#include <string.h>
18276707Sdes
19276707Sdes#include "../test_helper/test_helper.h"
20276707Sdes
21276707Sdes#include "ssherr.h"
22276707Sdes#include "sshbuf.h"
23276707Sdes
24276707Sdes#define NUM_FUZZ_TESTS (1 << 18)
25276707Sdes
26276707Sdesvoid sshbuf_fuzz_tests(void);
27276707Sdes
28276707Sdesvoid
29276707Sdessshbuf_fuzz_tests(void)
30276707Sdes{
31276707Sdes	struct sshbuf *p1;
32276707Sdes	u_char *dp;
33276707Sdes	size_t sz, sz2, i;
34276707Sdes	u_int32_t r;
35276707Sdes	int ret;
36276707Sdes
37276707Sdes	/* NB. uses sshbuf internals */
38276707Sdes	TEST_START("fuzz alloc/dealloc");
39276707Sdes	p1 = sshbuf_new();
40276707Sdes	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 16 * 1024), 0);
41276707Sdes	ASSERT_PTR_NE(p1, NULL);
42276707Sdes	ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
43276707Sdes	ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
44276707Sdes	for (i = 0; i < NUM_FUZZ_TESTS; i++) {
45276707Sdes		r = arc4random_uniform(10);
46276707Sdes		if (r == 0) {
47276707Sdes			/* 10% chance: small reserve */
48276707Sdes			r = arc4random_uniform(10);
49276707Sdes fuzz_reserve:
50276707Sdes			sz = sshbuf_avail(p1);
51276707Sdes			sz2 = sshbuf_len(p1);
52276707Sdes			ret = sshbuf_reserve(p1, r, &dp);
53276707Sdes			if (ret < 0) {
54276707Sdes				ASSERT_PTR_EQ(dp, NULL);
55276707Sdes				ASSERT_SIZE_T_LT(sz, r);
56276707Sdes				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz);
57276707Sdes				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2);
58276707Sdes			} else {
59276707Sdes				ASSERT_PTR_NE(dp, NULL);
60276707Sdes				ASSERT_SIZE_T_GE(sz, r);
61276707Sdes				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz - r);
62276707Sdes				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2 + r);
63276707Sdes				memset(dp, arc4random_uniform(255) + 1, r);
64276707Sdes			}
65276707Sdes		} else if (r < 3) {
66276707Sdes			/* 20% chance: big reserve */
67276707Sdes			r = arc4random_uniform(8 * 1024);
68276707Sdes			goto fuzz_reserve;
69276707Sdes		} else if (r == 3) {
70276707Sdes			/* 10% chance: small consume */
71276707Sdes			r = arc4random_uniform(10);
72276707Sdes fuzz_consume:
73276707Sdes			sz = sshbuf_avail(p1);
74276707Sdes			sz2 = sshbuf_len(p1);
75276707Sdes			/* 50% change consume from end, otherwise start */
76276707Sdes			ret = ((arc4random() & 1) ?
77276707Sdes			    sshbuf_consume : sshbuf_consume_end)(p1, r);
78276707Sdes			if (ret < 0) {
79276707Sdes				ASSERT_SIZE_T_LT(sz2, r);
80276707Sdes				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz);
81276707Sdes				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2);
82276707Sdes			} else {
83276707Sdes				ASSERT_SIZE_T_GE(sz2, r);
84276707Sdes				ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz + r);
85276707Sdes				ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2 - r);
86276707Sdes			}
87276707Sdes		} else if (r < 8) {
88276707Sdes			/* 40% chance: big consume */
89276707Sdes			r = arc4random_uniform(2 * 1024);
90276707Sdes			goto fuzz_consume;
91276707Sdes		} else if (r == 8) {
92276707Sdes			/* 10% chance: reset max size */
93276707Sdes			r = arc4random_uniform(16 * 1024);
94276707Sdes			sz = sshbuf_max_size(p1);
95276707Sdes			if (sshbuf_set_max_size(p1, r) < 0)
96276707Sdes				ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), sz);
97276707Sdes			else
98276707Sdes				ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), r);
99276707Sdes		} else {
100276707Sdes			if (arc4random_uniform(8192) == 0) {
101276707Sdes				/* tiny chance: new buffer */
102276707Sdes				ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
103276707Sdes				ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
104276707Sdes				sshbuf_free(p1);
105276707Sdes				p1 = sshbuf_new();
106276707Sdes				ASSERT_PTR_NE(p1, NULL);
107276707Sdes				ASSERT_INT_EQ(sshbuf_set_max_size(p1,
108276707Sdes				    16 * 1024), 0);
109276707Sdes			} else {
110276707Sdes				/* Almost 10%: giant reserve */
111276707Sdes				/* use arc4random_buf for r > 2^32 on 64 bit */
112276707Sdes				arc4random_buf(&r, sizeof(r));
113276707Sdes				while (r < SSHBUF_SIZE_MAX / 2) {
114276707Sdes					r <<= 1;
115276707Sdes					r |= arc4random() & 1;
116276707Sdes				}
117276707Sdes				goto fuzz_reserve;
118276707Sdes			}
119276707Sdes		}
120276707Sdes		ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
121276707Sdes		ASSERT_SIZE_T_LE(sshbuf_max_size(p1), 16 * 1024);
122276707Sdes	}
123276707Sdes	ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
124276707Sdes	ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
125276707Sdes	sshbuf_free(p1);
126276707Sdes	TEST_DONE();
127276707Sdes}
128