Update copyrights to 2021, using "make update-copyright"
[tor.git] / src / test / fuzz / fuzz_strops.c
blob02a74d1d8c041d084e149e1699f87ad24bae9bcf
1 /* Copyright (c) 2018-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 /**
5 * \file fuzz_strops.c
6 * \brief Fuzzers for various string encoding/decoding operations
7 **/
9 #include "orconfig.h"
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"
22 #include "test/fuzz/fuzzing.h"
24 #include <stdio.h>
25 #include <string.h>
27 int
28 fuzz_init(void)
30 return 0;
33 int
34 fuzz_cleanup(void)
36 return 0;
39 typedef struct chunk_t {
40 uint8_t *buf;
41 size_t len;
42 } chunk_t;
44 #define chunk_free(ch) \
45 FREE_AND_NULL(chunk_t, chunk_free_, (ch))
47 static chunk_t *
48 chunk_new(size_t len)
50 chunk_t *ch = tor_malloc(sizeof(chunk_t));
51 ch->buf = tor_malloc(len);
52 ch->len = len;
53 return ch;
55 static void
56 chunk_free_(chunk_t *ch)
58 if (!ch)
59 return;
60 tor_free(ch->buf);
61 tor_free(ch);
63 static bool
64 chunk_eq(const chunk_t *a, const chunk_t *b)
66 return a->len == b->len && fast_memeq(a->buf, b->buf, a->len);
69 static chunk_t *
70 b16_dec(const chunk_t *inp)
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);
79 return ch;
81 static chunk_t *
82 b16_enc(const chunk_t *inp)
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;
89 static chunk_t *
90 b32_dec(const chunk_t *inp)
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);
99 return ch;
101 static chunk_t *
102 b32_enc(const chunk_t *inp)
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;
110 static chunk_t *
111 b64_dec(const chunk_t *inp)
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);
120 return ch;
122 static chunk_t *
123 b64_enc(const chunk_t *inp)
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;
131 static chunk_t *
132 c_dec(const chunk_t *inp)
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);
143 return ch;
145 static chunk_t *
146 c_enc(const chunk_t *inp)
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;
156 static int kv_flags = 0;
157 static config_line_t *
158 kv_dec(const chunk_t *inp)
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;
165 static chunk_t *
166 kv_enc(const config_line_t *inp)
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;
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.
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; \
200 FREE(a); \
201 chunk_free(b); \
202 FREE(c); \
203 chunk_free(d); \
204 tor_assert(!err); \
205 } STMT_END
208 fuzz_main(const uint8_t *stdin_buf, size_t data_size)
210 if (!data_size)
211 return 0;
213 chunk_t inp = { (uint8_t*)stdin_buf, data_size };
214 chunk_t *b=NULL,*d=NULL;
215 void *a=NULL,*c=NULL;
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;
252 return 0;