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