fuzz.c revision 1.2.2.3 1 /* $NetBSD: fuzz.c,v 1.2.2.3 2019/01/18 08:49:11 pgoyette Exp $ */
2
3 /*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 * See the COPYRIGHT file distributed with this work for additional
11 * information regarding copyright ownership.
12 */
13
14 #include <config.h>
15
16 #include <inttypes.h>
17 #include <stdbool.h>
18
19 #include <named/fuzz.h>
20
21 #ifdef ENABLE_AFL
22 #include <named/globals.h>
23 #include <named/server.h>
24 #include <sys/errno.h>
25
26 #include <isc/app.h>
27 #include <isc/condition.h>
28 #include <isc/mutex.h>
29 #include <isc/thread.h>
30 #include <isc/util.h>
31 #include <named/log.h>
32 #include <dns/log.h>
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <signal.h>
37 #include <arpa/inet.h>
38 #include <unistd.h>
39 #include <pthread.h>
40
41 /*
42 * We are using pthreads directly because we might be using it with
43 * unthreaded version of BIND, where all thread functions are
44 * mocks. Since AFL for now only works on Linux it's not a problem.
45 */
46 static pthread_cond_t cond;
47 static pthread_mutex_t mutex;
48 static bool ready;
49
50 /*
51 * In "client:" mode, this thread reads fuzzed query messages from AFL
52 * from standard input and sends it to named's listening port (DNS) that
53 * is passed in the -A client:<address>:<port> option. It can be used to
54 * test named from the client side.
55 */
56 static void *
57 fuzz_thread_client(void *arg) {
58 char *host;
59 char *port;
60 struct sockaddr_in servaddr;
61 int sockfd;
62 void *buf;
63
64 UNUSED(arg);
65
66 /*
67 * Parse named -A argument in the "address:port" syntax. Due to
68 * the syntax used, this only supports IPv4 addresses.
69 */
70 host = strdup(named_g_fuzz_addr);
71 RUNTIME_CHECK(host != NULL);
72
73 port = strchr(host, ':');
74 RUNTIME_CHECK(port != NULL);
75 *port = 0;
76 ++port;
77
78 memset(&servaddr, 0, sizeof (servaddr));
79 servaddr.sin_family = AF_INET;
80 RUNTIME_CHECK(inet_pton(AF_INET, host, &servaddr.sin_addr) == 1);
81 servaddr.sin_port = htons(atoi(port));
82
83 free(host);
84
85 /*
86 * Wait for named to start. This is set in run_server() in the
87 * named thread.
88 */
89 while (!named_g_run_done) {
90 usleep(10000);
91 }
92
93 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
94 RUNTIME_CHECK(sockfd != -1);
95
96 buf = malloc(65536);
97 RUNTIME_CHECK(buf != NULL);
98
99 /*
100 * Processing fuzzed packets 100,000 times before shutting down
101 * the app.
102 */
103 #ifdef __AFL_LOOP
104 for (int loop = 0; loop < 100000; loop++) {
105 #else
106 {
107 #endif
108 ssize_t length;
109 ssize_t sent;
110
111 length = read(0, buf, 65536);
112 if (length <= 0) {
113 usleep(1000000);
114 goto next;
115 }
116
117 /*
118 * Ignore packets that are larger than 4096 bytes.
119 */
120 if (length > 4096) {
121 /*
122 * AFL_CMIN doesn't support persistent mode, so
123 * shutdown the server.
124 */
125 if (getenv("AFL_CMIN")) {
126 free(buf);
127 close(sockfd);
128 named_server_flushonshutdown(named_g_server,
129 false);
130 isc_app_shutdown();
131 return (NULL);
132 }
133 raise(SIGSTOP);
134 goto next;
135 }
136
137 RUNTIME_CHECK(pthread_mutex_lock(&mutex) == 0);
138
139 ready = false;
140
141 sent = sendto(sockfd, buf, length, 0,
142 (struct sockaddr *) &servaddr, sizeof(servaddr));
143 RUNTIME_CHECK(sent == length);
144
145 /*
146 * Read the reply message from named to unclog it. Don't
147 * bother if there isn't a reply.
148 */
149 recvfrom(sockfd, buf, 65536, MSG_DONTWAIT, NULL, NULL);
150
151 while (!ready)
152 pthread_cond_wait(&cond, &mutex);
153
154 RUNTIME_CHECK(pthread_mutex_unlock(&mutex) == 0);
155 next: ;
156 }
157
158 free(buf);
159 close(sockfd);
160
161 named_server_flushonshutdown(named_g_server, false);
162 isc_app_shutdown();
163
164 return (NULL);
165 }
166
167 /*
168 * In "resolver:" mode, this thread reads fuzzed reply messages from AFL
169 * from standard input. It also sets up a listener as a remote
170 * authoritative server and sends a driver query to the client side of
171 * named(resolver). When named(resolver) connects to this authoritative
172 * server, this thread writes the fuzzed reply message from AFL to it.
173 *
174 * -A resolver:<saddress>:<sport>:<raddress>:<rport>
175 *
176 * Here, <saddress>:<sport> is where named(resolver) is listening on.
177 * <raddress>:<rport> is where the thread is supposed to setup the
178 * authoritative server. This address should be configured via the root
179 * zone to be the authoritiative server for aaaaaaaaaa.example.
180 *
181 * named(resolver) when being fuzzed will not cache answers.
182 */
183 static void *
184 fuzz_thread_resolver(void *arg) {
185 char *sqtype, *shost, *sport, *rhost, *rport;
186 struct sockaddr_in servaddr, recaddr, recvaddr;
187 /*
188 * Query for aaaaaaaaaa.example./A in wire format with RD=1,
189 * EDNS and DO=1. 0x88, 0x0c at the start is the ID field which
190 * will be updated for each query.
191 */
192 char respacket[] = {
193 0x88, 0x0c, 0x01, 0x20, 0x00, 0x01, 0x00, 0x00,
194 0x00, 0x00, 0x00, 0x01, 0x0a, 0x61, 0x61, 0x61,
195 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x07,
196 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x00,
197 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x29, 0x10,
198 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00
199 };
200 /*
201 * Response for example./DNSKEY in wire format. Note that RRSIGs
202 * were generated with this DNSKEY that are used as seeds for
203 * AFL in the DNSSEC fuzzing job. So the DNSKEY content of this
204 * message must not change, or the corresponding RRSIGs will
205 * have to be updated. 0x8d, 0xf6 at the start is the ID field
206 * which will be made to match the query.
207 */
208 const uint8_t dnskey_wf[] = {
209 0x8d, 0xf6, 0x84, 0x00, 0x00, 0x01, 0x00, 0x02,
210 0x00, 0x00, 0x00, 0x01, 0x07, 0x65, 0x78, 0x61,
211 0x6d, 0x70, 0x6c, 0x65, 0x00, 0x00, 0x30, 0x00,
212 0x01, 0xc0, 0x0c, 0x00, 0x30, 0x00, 0x01, 0x00,
213 0x00, 0x01, 0x2c, 0x01, 0x08, 0x01, 0x00, 0x03,
214 0x08, 0x03, 0x01, 0x00, 0x01, 0xbd, 0x81, 0xdc,
215 0x7f, 0x16, 0xd4, 0x81, 0x7c, 0x1f, 0x9f, 0x6a,
216 0x68, 0xdd, 0xd4, 0xda, 0x48, 0xd9, 0x1c, 0xbd,
217 0xa6, 0x46, 0x1a, 0xf0, 0xb4, 0xb9, 0xec, 0x3d,
218 0x6c, 0x0b, 0x57, 0xc7, 0xd6, 0x54, 0x66, 0xe6,
219 0x6c, 0xd5, 0x90, 0x3a, 0x78, 0x7d, 0x7f, 0x78,
220 0x80, 0xa2, 0x89, 0x61, 0x6d, 0x8a, 0x2b, 0xcd,
221 0x0a, 0x77, 0x7a, 0xad, 0xc9, 0x61, 0x53, 0x53,
222 0x8c, 0x99, 0x72, 0x86, 0x14, 0x74, 0x9c, 0x49,
223 0x2a, 0x47, 0x23, 0xf7, 0x02, 0x07, 0x73, 0x1c,
224 0x5c, 0x2e, 0xb4, 0x9a, 0xa4, 0xd7, 0x98, 0x42,
225 0xc3, 0xd2, 0xfe, 0xbf, 0xf3, 0xb3, 0x6a, 0x52,
226 0x92, 0xd5, 0xfa, 0x47, 0x00, 0xe3, 0xd9, 0x59,
227 0x31, 0x95, 0x48, 0x40, 0xfc, 0x06, 0x73, 0x90,
228 0xc6, 0x73, 0x96, 0xba, 0x29, 0x91, 0xe2, 0xac,
229 0xa3, 0xa5, 0x6d, 0x91, 0x6d, 0x52, 0xb9, 0x34,
230 0xba, 0x68, 0x4f, 0xad, 0xf0, 0xc3, 0xf3, 0x1d,
231 0x6d, 0x61, 0x76, 0xe5, 0x3d, 0xa3, 0x9b, 0x2a,
232 0x0c, 0x92, 0xb3, 0x78, 0x6b, 0xf1, 0x20, 0xd6,
233 0x90, 0xb7, 0xac, 0xe2, 0xf8, 0x2b, 0x94, 0x10,
234 0x79, 0xce, 0xa8, 0x60, 0x42, 0xea, 0x6a, 0x18,
235 0x2f, 0xc0, 0xd8, 0x05, 0x0a, 0x3b, 0x06, 0x0f,
236 0x02, 0x7e, 0xff, 0x33, 0x46, 0xee, 0xb6, 0x21,
237 0x25, 0x90, 0x63, 0x4b, 0x3b, 0x5e, 0xb2, 0x72,
238 0x3a, 0xcb, 0x91, 0x41, 0xf4, 0x20, 0x50, 0x78,
239 0x1c, 0x93, 0x95, 0xda, 0xfa, 0xae, 0x85, 0xc5,
240 0xd7, 0x6b, 0x92, 0x0c, 0x70, 0x6b, 0xe4, 0xb7,
241 0x29, 0x3a, 0x2e, 0x18, 0x88, 0x82, 0x33, 0x7c,
242 0xa8, 0xea, 0xb8, 0x31, 0x8f, 0xaf, 0x50, 0xc5,
243 0x9c, 0x08, 0x56, 0x8f, 0x09, 0x76, 0x4e, 0xdf,
244 0x97, 0x75, 0x9d, 0x00, 0x52, 0x7f, 0xdb, 0xec,
245 0x30, 0xcb, 0x1c, 0x4c, 0x2a, 0x21, 0x93, 0xc4,
246 0x6d, 0x85, 0xa9, 0x40, 0x3b, 0xc0, 0x0c, 0x00,
247 0x2e, 0x00, 0x01, 0x00, 0x00, 0x01, 0x2c, 0x01,
248 0x1b, 0x00, 0x30, 0x08, 0x01, 0x00, 0x00, 0x01,
249 0x2c, 0x67, 0x74, 0x85, 0x80, 0x58, 0xb3, 0xc5,
250 0x17, 0x36, 0x90, 0x07, 0x65, 0x78, 0x61, 0x6d,
251 0x70, 0x6c, 0x65, 0x00, 0x45, 0xac, 0xd3, 0x82,
252 0x69, 0xf3, 0x10, 0x3a, 0x97, 0x2c, 0x6a, 0xa9,
253 0x78, 0x99, 0xea, 0xb0, 0xcc, 0xf7, 0xaf, 0x33,
254 0x51, 0x5b, 0xdf, 0x77, 0x04, 0x18, 0x14, 0x99,
255 0x61, 0xeb, 0x8d, 0x76, 0x3f, 0xd1, 0x71, 0x14,
256 0x43, 0x80, 0x53, 0xc2, 0x3b, 0x9f, 0x09, 0x4f,
257 0xb3, 0x51, 0x04, 0x89, 0x0e, 0xc8, 0x54, 0x12,
258 0xcd, 0x07, 0x20, 0xbe, 0x94, 0xc2, 0xda, 0x99,
259 0xdd, 0x1e, 0xf8, 0xb0, 0x84, 0x2e, 0xf9, 0x19,
260 0x35, 0x36, 0xf5, 0xd0, 0x5d, 0x82, 0x18, 0x74,
261 0xa0, 0x00, 0xb6, 0x15, 0x57, 0x40, 0x5f, 0x78,
262 0x2d, 0x27, 0xac, 0xc7, 0x8a, 0x29, 0x55, 0xa9,
263 0xcd, 0xbc, 0xf7, 0x3e, 0xff, 0xae, 0x1a, 0x5a,
264 0x1d, 0xac, 0x0d, 0x78, 0x0e, 0x08, 0x33, 0x6c,
265 0x59, 0x70, 0x40, 0xb9, 0x65, 0xbd, 0x35, 0xbb,
266 0x9a, 0x70, 0xdc, 0x93, 0x66, 0xb0, 0xef, 0xfe,
267 0xf0, 0x32, 0xa6, 0xee, 0xb7, 0x03, 0x89, 0xa2,
268 0x4d, 0xe0, 0xf1, 0x20, 0xdf, 0x39, 0xe8, 0xe3,
269 0xcc, 0x95, 0xe9, 0x9a, 0xad, 0xbf, 0xbd, 0x7c,
270 0xf7, 0xd7, 0xde, 0x47, 0x9e, 0xf6, 0x17, 0xbb,
271 0x84, 0xa9, 0xed, 0xf2, 0x45, 0x61, 0x6d, 0x13,
272 0x0b, 0x06, 0x29, 0x50, 0xde, 0xfd, 0x42, 0xb0,
273 0x66, 0x2c, 0x1c, 0x2b, 0x63, 0xcb, 0x4e, 0xb9,
274 0x31, 0xc4, 0xea, 0xd2, 0x07, 0x3a, 0x08, 0x79,
275 0x19, 0x4b, 0x4c, 0x50, 0x97, 0x02, 0xd7, 0x26,
276 0x41, 0x2f, 0xdd, 0x57, 0xaa, 0xb0, 0xa0, 0x21,
277 0x4e, 0x74, 0xb6, 0x97, 0x4b, 0x8b, 0x09, 0x9c,
278 0x3d, 0x29, 0xfb, 0x12, 0x27, 0x47, 0x8f, 0xb8,
279 0xc5, 0x8e, 0x65, 0xcd, 0xca, 0x2f, 0xba, 0xf5,
280 0x3e, 0xec, 0x56, 0xc3, 0xc9, 0xa1, 0x62, 0x7d,
281 0xf2, 0x9f, 0x90, 0x16, 0x1d, 0xbf, 0x97, 0x28,
282 0xe1, 0x92, 0xb1, 0x53, 0xab, 0xc4, 0xe0, 0x99,
283 0xbb, 0x19, 0x90, 0x7c, 0x00, 0x00, 0x29, 0x10,
284 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00
285 };
286
287 int sockfd;
288 int listenfd;
289 int loop;
290 uint16_t qtype;
291 char *buf, *rbuf;
292 char *nameptr;
293 unsigned int i;
294 uint8_t llen;
295 uint64_t seed;
296
297 UNUSED(arg);
298
299 /*
300 * Parse named -A argument in the "qtype:saddress:sport:raddress:rport"
301 * syntax. Due to the syntax used, this only supports IPv4 addresses.
302 */
303 sqtype = strdup(named_g_fuzz_addr);
304 RUNTIME_CHECK(sqtype != NULL);
305
306 shost = strchr(sqtype, ':');
307 RUNTIME_CHECK(shost != NULL);
308 *shost = 0;
309 shost++;
310
311 sport = strchr(shost, ':');
312 RUNTIME_CHECK(sport != NULL);
313 *sport = 0;
314 sport++;
315
316 rhost = strchr(sport, ':');
317 RUNTIME_CHECK(rhost != NULL);
318 *rhost = 0;
319 rhost++;
320
321 rport = strchr(rhost, ':');
322 RUNTIME_CHECK(rport != NULL);
323 *rport = 0;
324 rport++;
325
326 /*
327 * Patch in the qtype into the question section of respacket.
328 */
329 qtype = atoi(sqtype);
330 respacket[32] = (qtype >> 8) & 0xff;
331 respacket[33] = qtype & 0xff;
332
333 memset(&servaddr, 0, sizeof (servaddr));
334 servaddr.sin_family = AF_INET;
335 RUNTIME_CHECK(inet_pton(AF_INET, shost, &servaddr.sin_addr) == 1);
336 servaddr.sin_port = htons(atoi(sport));
337
338 memset(&recaddr, 0, sizeof (recaddr));
339 recaddr.sin_family = AF_INET;
340 RUNTIME_CHECK(inet_pton(AF_INET, rhost, &recaddr.sin_addr) == 1);
341 recaddr.sin_port = htons(atoi(rport));
342
343 free(sqtype);
344
345 /*
346 * Wait for named to start. This is set in run_server() in the
347 * named thread.
348 */
349 while (!named_g_run_done) {
350 usleep(10000);
351 }
352
353 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
354 RUNTIME_CHECK(sockfd != -1);
355
356 listenfd = socket(AF_INET, SOCK_DGRAM, 0);
357 RUNTIME_CHECK(listenfd != -1);
358
359 RUNTIME_CHECK(bind(listenfd, (struct sockaddr *)&recaddr,
360 sizeof(struct sockaddr_in)) == 0);
361
362 buf = malloc(65536);
363 rbuf = malloc(65536);
364 RUNTIME_CHECK(buf != NULL);
365 RUNTIME_CHECK(rbuf != NULL);
366
367 seed = 42;
368
369 /*
370 * Processing fuzzed packets 100,000 times before shutting down
371 * the app.
372 */
373 for (loop = 0; loop < 100000; loop++) {
374 ssize_t length;
375 ssize_t sent;
376 unsigned short id;
377 socklen_t socklen;
378
379 memset(buf, 0, 12);
380 length = read(0, buf, 65536);
381 if (length <= 0) {
382 usleep(1000000);
383 continue;
384 }
385
386 if (length > 4096) {
387 if (getenv("AFL_CMIN")) {
388 free(buf);
389 free(rbuf);
390 close(sockfd);
391 close(listenfd);
392 named_server_flushonshutdown(named_g_server,
393 false);
394 isc_app_shutdown();
395 return (NULL);
396 }
397 raise(SIGSTOP);
398 continue;
399 }
400
401 if (length < 12) {
402 length = 12;
403 }
404
405 RUNTIME_CHECK(pthread_mutex_lock(&mutex) == 0);
406
407 ready = false;
408
409 /* Use a unique query ID. */
410 seed = 1664525 * seed + 1013904223;
411 id = seed & 0xffff;
412 respacket[0] = (id >> 8) & 0xff;
413 respacket[1] = id & 0xff;
414
415 /*
416 * Flush any pending data on the authoritative server.
417 */
418 socklen = sizeof(recvaddr);
419 sent = recvfrom(listenfd, rbuf, 65536, MSG_DONTWAIT,
420 (struct sockaddr *) &recvaddr, &socklen);
421
422 /*
423 * Send a fixed client query to named(resolver) of
424 * aaaaaaaaaa.example./A. This is the starting query
425 * driver.
426 */
427 sent = sendto(sockfd, respacket, sizeof(respacket), 0,
428 (struct sockaddr *) &servaddr, sizeof(servaddr));
429 RUNTIME_CHECK(sent == sizeof(respacket));
430
431 /*
432 * named(resolver) will process the query above and send
433 * an upstream query to the authoritative server. We
434 * handle that here as the upstream authoritative server
435 * on listenfd.
436 */
437 socklen = sizeof(recvaddr);
438 sent = recvfrom(listenfd, rbuf, 65536, 0,
439 (struct sockaddr *) &recvaddr, &socklen);
440 RUNTIME_CHECK(sent > 0);
441
442 /*
443 * Copy QID and set QR so that response is always
444 * accepted by named(resolver).
445 */
446 buf[0] = rbuf[0];
447 buf[1] = rbuf[1];
448 buf[2] |= 0x80;
449
450 /*
451 * NOTE: We are not copying the QNAME or setting
452 * rcode=NOERROR each time. So the resolver may fail the
453 * client query (driver) / wander due to this. AA flag
454 * may also not be set based on the contents of the AFL
455 * fuzzed packet.
456 */
457
458 /*
459 * A hack - set QTYPE to the one from query so that we
460 * can easily share packets between instances. If we
461 * write over something else we'll get FORMERR anyway.
462 */
463
464 /* Skip DNS header to get to the name */
465 nameptr = buf + 12;
466
467 /* Skip the name to get to the qtype */
468 i = 0;
469 while (((llen = nameptr[i]) != 0) &&
470 (i < 255) &&
471 (((nameptr + i + 1 + llen) - buf) < length))
472 i += 1 + llen;
473
474 if (i <= 255) {
475 nameptr += 1 + i;
476 /* Patch the qtype */
477 if ((nameptr - buf) < (length - 2)) {
478 *nameptr++ = (qtype >> 8) & 0xff;
479 *nameptr++ = qtype & 0xff;
480 }
481 /* Patch the qclass */
482 if ((nameptr - buf) < (length - 2)) {
483 *nameptr++ = 0;
484 *nameptr++ = 1;
485 }
486 }
487
488 /*
489 * Send the reply to named(resolver).
490 */
491 sent = sendto(listenfd, buf, length, 0,
492 (struct sockaddr *) &recvaddr, sizeof(recvaddr));
493 RUNTIME_CHECK(sent == length);
494
495 /* We might get additional questions here (e.g. for CNAME). */
496 for (;;) {
497 fd_set fds;
498 struct timeval tv;
499 int rv;
500 int max;
501
502 FD_ZERO(&fds);
503 FD_SET(listenfd, &fds);
504 FD_SET(sockfd, &fds);
505 tv.tv_sec = 10;
506 tv.tv_usec = 0;
507 max = (listenfd > sockfd ? listenfd : sockfd)+1;
508
509 rv = select(max, &fds, NULL, NULL, &tv);
510 RUNTIME_CHECK(rv > 0);
511
512 if (FD_ISSET(sockfd, &fds)) {
513 /*
514 * It's the reply from named(resolver)
515 * to the client(query driver), so we're
516 * done.
517 */
518 recvfrom(sockfd, buf, 65536, 0, NULL, NULL);
519 break;
520 }
521
522 /*
523 * We've got additional question (eg. due to
524 * CNAME). Bounce it - setting QR flag and
525 * NOERROR rcode and sending it back.
526 */
527 length = recvfrom(listenfd, buf, 65536, 0,
528 (struct sockaddr *) &recvaddr, &socklen);
529
530 /*
531 * If this is a DNSKEY query, send the DNSKEY,
532 * otherwise, bounce the query.
533 */
534
535 /* Skip DNS header to get to the name */
536 nameptr = buf + 12;
537
538 /* Skip the name to get to the qtype */
539 i = 0;
540 while (((llen = nameptr[i]) != 0) &&
541 (i < 255) &&
542 (((nameptr + i + 1 + llen) - buf) < length))
543 i += 1 + llen;
544
545 if (i <= 255) {
546 nameptr += 1 + i;
547 /*
548 * Patch in the DNSKEY reply without
549 * touching the ID field. Note that we
550 * don't compare the name in the
551 * question section in the query, but we
552 * don't expect to receive any query for
553 * type DNSKEY but for the name
554 * "example."
555 */
556 if ((nameptr - buf) < (length - 2)) {
557 uint8_t hb, lb;
558 hb = *nameptr++;
559 lb = *nameptr++;
560 qtype = (hb << 8) | lb;
561
562 if (qtype == 48) {
563 memmove(buf + 2, dnskey_wf + 2,
564 sizeof (dnskey_wf) - 2);
565 length = sizeof (dnskey_wf);
566 }
567 }
568 }
569
570 buf[2] |= 0x80;
571 buf[3] &= 0xF0;
572 sent = sendto(listenfd, buf, length, 0,
573 (struct sockaddr *) &recvaddr,
574 sizeof(recvaddr));
575 RUNTIME_CHECK(sent == length);
576 }
577
578 while (!ready)
579 pthread_cond_wait(&cond, &mutex);
580
581 RUNTIME_CHECK(pthread_mutex_unlock(&mutex) == 0);
582 }
583
584 free(buf);
585 free(rbuf);
586 close(sockfd);
587 close(listenfd);
588 named_server_flushonshutdown(named_g_server, false);
589 isc_app_shutdown();
590
591 #ifdef __AFL_LOOP
592 /*
593 * This is here just for the signature, that's how AFL detects
594 * if it's a 'persistent mode' binary. It has to occur somewhere
595 * in the file, that's all. < wpk_> AFL checks the binary for
596 * this signature ("##SIG_AFL_PERSISTENT##") and runs the binary
597 * in persistent mode if it's present.
598 */
599 __AFL_LOOP(0);
600 #endif
601
602 return (NULL);
603 }
604
605 /*
606 * In "tcp:", "http:" and "rndc:" modes, this thread reads fuzzed query
607 * blobs from AFL from standard input and sends it to the corresponding
608 * TCP listening port of named (port 53 DNS, or the HTTP statistics
609 * channels listener or the rndc port) that is passed in the -A
610 * <mode>:<address>:<port> option. It can be used to test named from the
611 * client side.
612 */
613 static void *
614 fuzz_thread_tcp(void *arg) {
615 char *host;
616 char *port;
617 struct sockaddr_in servaddr;
618 int sockfd;
619 char *buf;
620 int loop;
621
622 UNUSED(arg);
623
624 /*
625 * Parse named -A argument in the "address:port" syntax. Due to
626 * the syntax used, this only supports IPv4 addresses.
627 */
628 host = strdup(named_g_fuzz_addr);
629 RUNTIME_CHECK(host != NULL);
630
631 port = strchr(host, ':');
632 RUNTIME_CHECK(port != NULL);
633 *port = 0;
634 ++port;
635
636 memset(&servaddr, 0, sizeof (servaddr));
637 servaddr.sin_family = AF_INET;
638 RUNTIME_CHECK(inet_pton(AF_INET, host, &servaddr.sin_addr) == 1);
639 servaddr.sin_port = htons(atoi(port));
640
641 free(host);
642
643 /*
644 * Wait for named to start. This is set in run_server() in the
645 * named thread.
646 */
647 while (!named_g_run_done) {
648 usleep(10000);
649 }
650
651 buf = malloc(65539);
652 RUNTIME_CHECK(buf != NULL);
653
654 /*
655 * Processing fuzzed packets 100,000 times before shutting down
656 * the app.
657 */
658 for (loop = 0; loop < 100000; loop++) {
659 ssize_t length;
660 ssize_t sent;
661 int yes;
662 int r;
663
664 if (named_g_fuzz_type == isc_fuzz_tcpclient) {
665 /*
666 * To fuzz DNS TCP client we have to put 16-bit
667 * message length preceding the start of packet.
668 */
669 length = read(0, buf+2, 65535);
670 buf[0] = (length >> 8) & 0xff;
671 buf[1] = length & 0xff;
672 length += 2;
673 } else {
674 /*
675 * Other types of TCP clients such as HTTP, etc.
676 */
677 length = read(0, buf, 65535);
678 }
679 if (length <= 0) {
680 usleep(1000000);
681 continue;
682 }
683 if (named_g_fuzz_type == isc_fuzz_http) {
684 /*
685 * This guarantees that the request will be
686 * processed.
687 */
688 INSIST(length <= 65535);
689 buf[length++]='\r';
690 buf[length++]='\n';
691 buf[length++]='\r';
692 buf[length++]='\n';
693 }
694
695 RUNTIME_CHECK(pthread_mutex_lock(&mutex) == 0);
696
697 ready = false;
698 yes = 1;
699 sockfd = socket(AF_INET, SOCK_STREAM, 0);
700
701 RUNTIME_CHECK(sockfd != -1);
702 RUNTIME_CHECK(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
703 &yes, sizeof(int)) == 0);
704
705 do {
706 r = connect(sockfd, (struct sockaddr*)&servaddr,
707 sizeof(servaddr));
708 if (r != 0)
709 usleep(10000);
710 } while (r != 0);
711
712 /*
713 * Send the fuzzed query blob to the target server.
714 */
715 sent = write(sockfd, buf, length);
716 RUNTIME_CHECK(sent == length);
717
718 close(sockfd);
719
720 while (!ready)
721 pthread_cond_wait(&cond, &mutex);
722
723 RUNTIME_CHECK(pthread_mutex_unlock(&mutex) == 0);
724 }
725
726 free(buf);
727 close(sockfd);
728 named_server_flushonshutdown(named_g_server, false);
729 isc_app_shutdown();
730
731 return (NULL);
732 }
733
734 #endif /* ENABLE_AFL */
735
736 /*
737 * named has finished processing a message and has sent the
738 * reply. Signal the fuzz thread using the condition variable, to read
739 * and process the next item from AFL.
740 */
741 void
742 named_fuzz_notify(void) {
743 #ifdef ENABLE_AFL
744 if (getenv("AFL_CMIN")) {
745 named_server_flushonshutdown(named_g_server, false);
746 isc_app_shutdown();
747 return;
748 }
749
750 raise(SIGSTOP);
751
752 RUNTIME_CHECK(pthread_mutex_lock(&mutex) == 0);
753
754 ready = true;
755
756 RUNTIME_CHECK(pthread_cond_signal(&cond) == 0);
757 RUNTIME_CHECK(pthread_mutex_unlock(&mutex) == 0);
758 #endif /* ENABLE_AFL */
759 }
760
761 void
762 named_fuzz_setup(void) {
763 #ifdef ENABLE_AFL
764 if (getenv("__AFL_PERSISTENT") || getenv("AFL_CMIN")) {
765 pthread_t thread;
766 void *(fn) = NULL;
767
768 switch (named_g_fuzz_type) {
769 case isc_fuzz_client:
770 fn = fuzz_thread_client;
771 break;
772
773 case isc_fuzz_http:
774 case isc_fuzz_tcpclient:
775 case isc_fuzz_rndc:
776 fn = fuzz_thread_tcp;
777 break;
778
779 case isc_fuzz_resolver:
780 fn = fuzz_thread_resolver;
781 break;
782
783 default:
784 RUNTIME_CHECK(fn != NULL);
785 }
786
787 RUNTIME_CHECK(pthread_mutex_init(&mutex, NULL) == 0);
788 RUNTIME_CHECK(pthread_cond_init(&cond, NULL) == 0);
789 RUNTIME_CHECK(pthread_create(&thread, NULL, fn, NULL) == 0);
790 }
791 #endif /* ENABLE_AFL */
792 }
793