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 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