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