fuzz_strops.c (6211B)
1 /* Copyright (c) 2018-2021, The Tor Project, Inc. */ 2 /* See LICENSE for licensing information */ 3 4 /** 5 * \file fuzz_strops.c 6 * \brief Fuzzers for various string encoding/decoding operations 7 **/ 8 9 #include "orconfig.h" 10 11 #include "lib/cc/torint.h" 12 #include "lib/ctime/di_ops.h" 13 #include "lib/encoding/binascii.h" 14 #include "lib/encoding/cstring.h" 15 #include "lib/encoding/kvline.h" 16 #include "lib/encoding/confline.h" 17 #include "lib/malloc/malloc.h" 18 #include "lib/log/escape.h" 19 #include "lib/log/util_bug.h" 20 #include "lib/intmath/muldiv.h" 21 22 #include "test/fuzz/fuzzing.h" 23 24 #include <stdio.h> 25 #include <string.h> 26 27 int 28 fuzz_init(void) 29 { 30 return 0; 31 } 32 33 int 34 fuzz_cleanup(void) 35 { 36 return 0; 37 } 38 39 typedef struct chunk_t { 40 uint8_t *buf; 41 size_t len; 42 } chunk_t; 43 44 #define chunk_free(ch) \ 45 FREE_AND_NULL(chunk_t, chunk_free_, (ch)) 46 47 static chunk_t * 48 chunk_new(size_t len) 49 { 50 chunk_t *ch = tor_malloc(sizeof(chunk_t)); 51 ch->buf = tor_malloc(len); 52 ch->len = len; 53 return ch; 54 } 55 static void 56 chunk_free_(chunk_t *ch) 57 { 58 if (!ch) 59 return; 60 tor_free(ch->buf); 61 tor_free(ch); 62 } 63 static bool 64 chunk_eq(const chunk_t *a, const chunk_t *b) 65 { 66 return a->len == b->len && fast_memeq(a->buf, b->buf, a->len); 67 } 68 69 static chunk_t * 70 b16_dec(const chunk_t *inp) 71 { 72 chunk_t *ch = chunk_new(CEIL_DIV(inp->len, 2)); 73 int r = base16_decode((char *)ch->buf, ch->len, (char *)inp->buf, inp->len); 74 if (r >= 0) { 75 ch->len = r; 76 } else { 77 chunk_free(ch); 78 } 79 return ch; 80 } 81 static chunk_t * 82 b16_enc(const chunk_t *inp) 83 { 84 chunk_t *ch = chunk_new(inp->len * 2 + 1); 85 base16_encode((char *)ch->buf, ch->len, (char*)inp->buf, inp->len); 86 return ch; 87 } 88 89 static chunk_t * 90 b32_dec(const chunk_t *inp) 91 { 92 chunk_t *ch = chunk_new(inp->len);//XXXX 93 int r = base32_decode((char *)ch->buf, ch->len, (char *)inp->buf, inp->len); 94 if (r >= 0) { 95 ch->len = r; 96 } else { 97 chunk_free(ch); 98 } 99 return ch; 100 } 101 static chunk_t * 102 b32_enc(const chunk_t *inp) 103 { 104 chunk_t *ch = chunk_new(base32_encoded_size(inp->len)); 105 base32_encode((char *)ch->buf, ch->len, (char*)inp->buf, inp->len); 106 ch->len = strlen((char *) ch->buf); 107 return ch; 108 } 109 110 static chunk_t * 111 b64_dec(const chunk_t *inp) 112 { 113 chunk_t *ch = chunk_new(inp->len);//XXXX This could be shorter. 114 int r = base64_decode((char *)ch->buf, ch->len, (char *)inp->buf, inp->len); 115 if (r >= 0) { 116 ch->len = r; 117 } else { 118 chunk_free(ch); 119 } 120 return ch; 121 } 122 static chunk_t * 123 b64_enc(const chunk_t *inp) 124 { 125 chunk_t *ch = chunk_new(BASE64_BUFSIZE(inp->len)); 126 base64_encode((char *)ch->buf, ch->len, (char *)inp->buf, inp->len, 0); 127 ch->len = strlen((char *) ch->buf); 128 return ch; 129 } 130 131 static chunk_t * 132 c_dec(const chunk_t *inp) 133 { 134 char *s = tor_memdup_nulterm(inp->buf, inp->len); 135 chunk_t *ch = tor_malloc(sizeof(chunk_t)); 136 char *r = NULL; 137 (void) unescape_string(s, &r, &ch->len); 138 tor_free(s); 139 ch->buf = (uint8_t*) r; 140 if (!ch->buf) { 141 tor_free(ch); 142 } 143 return ch; 144 } 145 static chunk_t * 146 c_enc(const chunk_t *inp) 147 { 148 char *s = tor_memdup_nulterm(inp->buf, inp->len); 149 chunk_t *ch = tor_malloc(sizeof(chunk_t)); 150 ch->buf = (uint8_t*)esc_for_log(s); 151 tor_free(s); 152 ch->len = strlen((char*)ch->buf); 153 return ch; 154 } 155 156 static int kv_flags = 0; 157 static config_line_t * 158 kv_dec(const chunk_t *inp) 159 { 160 char *s = tor_memdup_nulterm(inp->buf, inp->len); 161 config_line_t *res = kvline_parse(s, kv_flags); 162 tor_free(s); 163 return res; 164 } 165 static chunk_t * 166 kv_enc(const config_line_t *inp) 167 { 168 char *s = kvline_encode(inp, kv_flags); 169 if (!s) 170 return NULL; 171 chunk_t *res = tor_malloc(sizeof(chunk_t)); 172 res->buf = (uint8_t*)s; 173 res->len = strlen(s); 174 return res; 175 } 176 177 /* Given an encoder function, a decoder function, and a function to free 178 * the decoded object, check whether any string that successfully decoded 179 * will then survive an encode-decode-encode round-trip unchanged. 180 */ 181 #define ENCODE_ROUNDTRIP(E,D,FREE) \ 182 STMT_BEGIN { \ 183 bool err = false; \ 184 a = D(&inp); \ 185 if (!a) \ 186 return 0; \ 187 b = E(a); \ 188 tor_assert(b); \ 189 c = D(b); \ 190 tor_assert(c); \ 191 d = E(c); \ 192 tor_assert(d); \ 193 if (!chunk_eq(b,d)) { \ 194 printf("Unequal chunks: %s\n", \ 195 hex_str((char*)b->buf, b->len)); \ 196 printf(" vs %s\n", \ 197 hex_str((char*)d->buf, d->len)); \ 198 err = true; \ 199 } \ 200 FREE(a); \ 201 chunk_free(b); \ 202 FREE(c); \ 203 chunk_free(d); \ 204 tor_assert(!err); \ 205 } STMT_END 206 207 int 208 fuzz_main(const uint8_t *stdin_buf, size_t data_size) 209 { 210 if (!data_size) 211 return 0; 212 213 chunk_t inp = { (uint8_t*)stdin_buf, data_size }; 214 chunk_t *b=NULL,*d=NULL; 215 void *a=NULL,*c=NULL; 216 217 switch (stdin_buf[0]) { 218 case 0: 219 ENCODE_ROUNDTRIP(b16_enc, b16_dec, chunk_free_); 220 break; 221 case 1: 222 ENCODE_ROUNDTRIP(b32_enc, b32_dec, chunk_free_); 223 break; 224 case 2: 225 ENCODE_ROUNDTRIP(b64_enc, b64_dec, chunk_free_); 226 break; 227 case 3: 228 ENCODE_ROUNDTRIP(c_enc, c_dec, chunk_free_); 229 break; 230 case 5: 231 kv_flags = KV_QUOTED|KV_OMIT_KEYS; 232 ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_); 233 break; 234 case 6: 235 kv_flags = 0; 236 ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_); 237 break; 238 case 7: 239 kv_flags = KV_OMIT_VALS; 240 ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_); 241 break; 242 case 8: 243 kv_flags = KV_QUOTED; 244 ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_); 245 break; 246 case 9: 247 kv_flags = KV_QUOTED|KV_OMIT_VALS; 248 ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_); 249 break; 250 } 251 252 return 0; 253 }