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
fuzz_init(void)28 fuzz_init(void)
29 {
30 return 0;
31 }
32
33 int
fuzz_cleanup(void)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 *
chunk_new(size_t len)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
chunk_free_(chunk_t * ch)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
chunk_eq(const chunk_t * a,const chunk_t * b)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 *
b16_dec(const chunk_t * inp)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 *
b16_enc(const chunk_t * inp)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 *
b32_dec(const chunk_t * inp)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 *
b32_enc(const chunk_t * inp)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 *
b64_dec(const chunk_t * inp)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 *
b64_enc(const chunk_t * inp)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 *
c_dec(const chunk_t * inp)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 *
c_enc(const chunk_t * inp)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 *
kv_dec(const chunk_t * inp)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 *
kv_enc(const config_line_t * inp)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
fuzz_main(const uint8_t * stdin_buf,size_t data_size)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 }
254