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