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