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