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