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