1 /* 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2018, 2019 Andrew Turner 5 * 6 * This software was developed by SRI International and the University of 7 * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 8 * ("CTSRD"), as part of the DARPA CRASH research programme. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 #include <sys/cdefs.h> 32 33 #include <sys/param.h> 34 #include <sys/ioctl.h> 35 #include <sys/kcov.h> 36 #include <sys/mman.h> 37 38 #include <errno.h> 39 #include <fcntl.h> 40 #include <pthread.h> 41 #include <semaphore.h> 42 #include <unistd.h> 43 44 #include <atf-c.h> 45 46 #define PAGE_SIZE sysconf(_SC_PAGESIZE) 47 48 static int 49 open_kcov(void) 50 { 51 int fd; 52 53 fd = open("/dev/kcov", O_RDWR); 54 if (fd == -1) 55 atf_tc_skip("Failed to open /dev/kcov"); 56 57 return fd; 58 } 59 60 static int 61 pick_unassigned_fd(int greater_than_fd) 62 { 63 int fd2; 64 65 fd2 = greater_than_fd; 66 do { 67 ++fd2; 68 } while (fcntl(fd2, F_GETFL) != -1 || errno != EBADF); 69 70 return fd2; 71 } 72 73 ATF_TC_WITHOUT_HEAD(kcov_dup2); 74 ATF_TC_BODY(kcov_dup2, tc) 75 { 76 int fd1, fd2; 77 fd1 = open_kcov(); 78 79 fd2 = pick_unassigned_fd(fd1); 80 81 /* Test the dup2(2) trick used by syzkaller */ 82 ATF_REQUIRE_EQ(dup2(fd1, fd2), fd2); 83 84 close(fd1); 85 close(fd2); 86 } 87 88 ATF_TC_WITHOUT_HEAD(kcov_multiopen); 89 ATF_TC_BODY(kcov_multiopen, tc) 90 { 91 int fd1, fd2; 92 fd1 = open_kcov(); 93 94 fd2 = open("/dev/kcov", O_RDWR); 95 ATF_REQUIRE(fd2 != -1); 96 97 close(fd1); 98 close(fd2); 99 } 100 101 ATF_TC_WITHOUT_HEAD(kcov_open_close_open); 102 ATF_TC_BODY(kcov_open_close_open, tc) 103 { 104 int fd; 105 106 fd = open_kcov(); 107 close(fd); 108 fd = open("/dev/kcov", O_RDWR); 109 ATF_REQUIRE(fd != -1); 110 111 close(fd); 112 } 113 114 ATF_TC_WITHOUT_HEAD(kcov_bufsize); 115 ATF_TC_BODY(kcov_bufsize, tc) 116 { 117 int fd; 118 uint64_t size; 119 fd = open_kcov(); 120 121 size = 0; 122 ATF_CHECK(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == -1); 123 size = 2; 124 ATF_CHECK(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0); 125 126 close(fd); 127 } 128 129 ATF_TC_WITHOUT_HEAD(kcov_mmap); 130 ATF_TC_BODY(kcov_mmap, tc) 131 { 132 void *data; 133 int fd; 134 uint64_t size = 2 * PAGE_SIZE / KCOV_ENTRY_SIZE; 135 136 fd = open_kcov(); 137 138 ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, 139 fd, 0) == MAP_FAILED); 140 141 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0); 142 143 ATF_REQUIRE((data = mmap(NULL, 2 * PAGE_SIZE, PROT_READ | PROT_WRITE, 144 MAP_SHARED, fd, 0)) != MAP_FAILED); 145 146 munmap(data, 2 * PAGE_SIZE); 147 148 close(fd); 149 } 150 151 /* This shouldn't panic */ 152 ATF_TC_WITHOUT_HEAD(kcov_mmap_no_munmap); 153 ATF_TC_BODY(kcov_mmap_no_munmap, tc) 154 { 155 int fd; 156 uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE; 157 158 fd = open_kcov(); 159 160 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0); 161 162 ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, 163 fd, 0) != MAP_FAILED); 164 165 close(fd); 166 } 167 168 ATF_TC_WITHOUT_HEAD(kcov_mmap_no_munmap_no_close); 169 ATF_TC_BODY(kcov_mmap_no_munmap_no_close, tc) 170 { 171 int fd; 172 uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE; 173 174 fd = open_kcov(); 175 176 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0); 177 178 ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, 179 fd, 0) != MAP_FAILED); 180 } 181 182 static sem_t sem1, sem2; 183 184 static void * 185 kcov_mmap_enable_thread(void *data) 186 { 187 int fd; 188 uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE; 189 int mode; 190 191 fd = open_kcov(); 192 *(int *)data = fd; 193 194 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0); 195 ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, 196 fd, 0) != MAP_FAILED); 197 mode = KCOV_MODE_NONE; 198 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0); 199 200 sem_post(&sem1); 201 sem_wait(&sem2); 202 203 return NULL; 204 } 205 206 ATF_TC_WITHOUT_HEAD(kcov_mmap_enable_thread_close); 207 ATF_TC_BODY(kcov_mmap_enable_thread_close, tc) 208 { 209 pthread_t thread; 210 int fd; 211 212 sem_init(&sem1, 0, 0); 213 sem_init(&sem2, 0, 0); 214 pthread_create(&thread, NULL, 215 kcov_mmap_enable_thread, &fd); 216 sem_wait(&sem1); 217 close(fd); 218 sem_post(&sem2); 219 pthread_join(thread, NULL); 220 } 221 222 ATF_TC_WITHOUT_HEAD(kcov_enable); 223 ATF_TC_BODY(kcov_enable, tc) 224 { 225 int fd; 226 uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE; 227 int mode; 228 229 fd = open_kcov(); 230 231 mode = KCOV_MODE_NONE; 232 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == -1); 233 234 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0); 235 236 /* We need to enable before disable */ 237 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == -1); 238 239 /* Check enabling works only with a valid trace method */ 240 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0); 241 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == -1); 242 243 /* Disable should only be called once */ 244 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0); 245 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == -1); 246 247 /* Re-enabling and changing mode should also work */ 248 mode = KCOV_MODE_NONE; 249 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0); 250 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0); 251 mode = KCOV_MODE_TRACE_PC; 252 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0); 253 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0); 254 mode = KCOV_MODE_TRACE_CMP; 255 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0); 256 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0); 257 258 close(fd); 259 } 260 261 ATF_TC_WITHOUT_HEAD(kcov_enable_no_disable); 262 ATF_TC_BODY(kcov_enable_no_disable, tc) 263 { 264 int fd; 265 uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE; 266 int mode; 267 268 fd = open_kcov(); 269 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0); 270 mode = KCOV_MODE_NONE; 271 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0); 272 close(fd); 273 } 274 275 ATF_TC_WITHOUT_HEAD(kcov_enable_no_disable_no_close); 276 ATF_TC_BODY(kcov_enable_no_disable_no_close, tc) 277 { 278 int fd; 279 uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE; 280 int mode; 281 282 fd = open_kcov(); 283 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0); 284 mode = KCOV_MODE_NONE; 285 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0); 286 } 287 288 static void * 289 common_head_raw(bool fd_dup, int *fdp) 290 { 291 void *data; 292 int fd, fd2; 293 uint64_t size = PAGE_SIZE / KCOV_ENTRY_SIZE; 294 295 fd = open_kcov(); 296 297 /* Test the dup2(2) trick used by syzkaller */ 298 if (fd_dup) { 299 fd2 = pick_unassigned_fd(fd); 300 ATF_REQUIRE_EQ(dup2(fd, fd2), fd2); 301 close(fd); 302 fd = fd2; 303 } 304 305 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0, 306 "Unable to set the kcov buffer size"); 307 308 data = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 309 ATF_REQUIRE_MSG(data != MAP_FAILED, "Unable to mmap the kcov buffer"); 310 311 *fdp = fd; 312 return data; 313 } 314 315 static void * 316 common_head(int *fdp) 317 { 318 319 return common_head_raw(false, fdp); 320 } 321 322 static void 323 common_tail(int fd, kcov_int_t *data) 324 { 325 326 ATF_REQUIRE_MSG(munmap(__UNVOLATILE(data), PAGE_SIZE) == 0, 327 "Unable to unmap the kcov buffer"); 328 329 close(fd); 330 } 331 332 static void 333 kcov_basic(bool fd_dup, int mode) 334 { 335 kcov_int_t *buf; 336 int fd; 337 338 buf = common_head_raw(fd_dup, &fd); 339 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0, 340 "Unable to enable kcov "); 341 342 buf[0] = 0; 343 344 sleep(0); /* XXX: Is it enough for all trace types? */ 345 ATF_REQUIRE_MSG(buf[0] != 0, "No records found"); 346 347 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_DISABLE) == 0, 348 "Unable to disable kcov"); 349 350 common_tail(fd, buf); 351 } 352 353 ATF_TC_WITHOUT_HEAD(kcov_basic_pc); 354 ATF_TC_BODY(kcov_basic_pc, tc) 355 { 356 357 kcov_basic(false, KCOV_MODE_TRACE_PC); 358 } 359 360 ATF_TC_WITHOUT_HEAD(kcov_basic_cmp); 361 ATF_TC_BODY(kcov_basic_cmp, tc) 362 { 363 364 atf_tc_skip("XXX: GCC8 needed"); 365 366 kcov_basic(false, KCOV_MODE_TRACE_CMP); 367 } 368 369 ATF_TC_WITHOUT_HEAD(kcov_basic_dup2_pc); 370 ATF_TC_BODY(kcov_basic_dup2_pc, tc) 371 { 372 373 kcov_basic(true, KCOV_MODE_TRACE_PC); 374 } 375 376 ATF_TC_WITHOUT_HEAD(kcov_basic_dup2_cmp); 377 ATF_TC_BODY(kcov_basic_dup2_cmp, tc) 378 { 379 380 atf_tc_skip("XXX: GCC8 needed"); 381 382 kcov_basic(true, KCOV_MODE_TRACE_CMP); 383 } 384 385 ATF_TC_WITHOUT_HEAD(kcov_multienable_on_the_same_thread); 386 ATF_TC_BODY(kcov_multienable_on_the_same_thread, tc) 387 { 388 kcov_int_t *buf1, *buf2; 389 int fd1, fd2; 390 int mode; 391 392 buf1 = common_head(&fd1); 393 buf2 = common_head(&fd2); 394 mode = KCOV_MODE_NONE; 395 ATF_REQUIRE_MSG(ioctl(fd1, KCOV_IOC_ENABLE, &mode) == 0, 396 "Unable to enable kcov"); 397 ATF_REQUIRE_ERRNO(EBUSY, ioctl(fd2, KCOV_IOC_ENABLE, &mode) != 0); 398 399 ATF_REQUIRE_MSG(ioctl(fd1, KCOV_IOC_DISABLE) == 0, 400 "Unable to disable kcov"); 401 402 common_tail(fd1, buf1); 403 common_tail(fd2, buf2); 404 } 405 406 static void * 407 thread_buffer_access_test_helper(void *ptr) 408 { 409 kcov_int_t *buf = ptr; 410 411 /* Test mapped buffer access from a custom thread */ 412 buf[0] = buf[0]; 413 414 return NULL; 415 } 416 417 ATF_TC_WITHOUT_HEAD(kcov_buffer_access_from_custom_thread); 418 ATF_TC_BODY(kcov_buffer_access_from_custom_thread, tc) 419 { 420 pthread_t thread; 421 kcov_int_t *buf; 422 int fd; 423 int mode; 424 425 buf = common_head(&fd); 426 427 mode = KCOV_MODE_TRACE_PC; 428 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0, 429 "Unable to enable kcov "); 430 431 pthread_create(&thread, NULL, thread_buffer_access_test_helper, 432 __UNVOLATILE(buf)); 433 pthread_join(thread, NULL); 434 435 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_DISABLE) == 0, 436 "Unable to disable kcov"); 437 438 common_tail(fd, buf); 439 } 440 441 static void * 442 thread_test_helper(void *ptr) 443 { 444 volatile int i; 445 446 /* It does not matter what operation is in action. */ 447 for (i = 0; i < 1000; i++) { 448 if (getpid() == 0) 449 break; 450 } 451 452 return NULL; 453 } 454 455 ATF_TC_WITHOUT_HEAD(kcov_thread); 456 ATF_TC_BODY(kcov_thread, tc) 457 { 458 pthread_t thread; 459 kcov_int_t *buf; 460 int fd; 461 int mode; 462 volatile int i; 463 464 buf = common_head(&fd); 465 466 mode = KCOV_MODE_TRACE_PC; 467 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0, 468 "Unable to enable kcov "); 469 470 /* The thread does something, does not matter what exactly. */ 471 pthread_create(&thread, NULL, thread_test_helper, __UNVOLATILE(buf)); 472 473 buf[0] = 0; 474 for (i = 0; i < 10000; i++) 475 continue; 476 ATF_REQUIRE_EQ_MSG(buf[0], 0, 477 "Records changed in blocked thread"); 478 479 pthread_join(thread, NULL); 480 481 ATF_REQUIRE_EQ_MSG(ioctl(fd, KCOV_IOC_DISABLE), 0, 482 "Unable to disable kcov"); 483 484 common_tail(fd, buf); 485 } 486 487 static void * 488 multiple_threads_helper(void *ptr __unused) 489 { 490 kcov_int_t *buf; 491 int fd; 492 int mode; 493 494 buf = common_head(&fd); 495 mode = KCOV_MODE_TRACE_PC; 496 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE, &mode) == 0, 497 "Unable to enable kcov "); 498 499 buf[0] = 0; 500 501 sleep(0); 502 ATF_REQUIRE_MSG(buf[0] != 0, "No records found"); 503 504 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_DISABLE) == 0, 505 "Unable to disable kcov"); 506 507 common_tail(fd, buf); 508 509 return NULL; 510 } 511 512 static void 513 kcov_multiple_threads(size_t N) 514 { 515 pthread_t thread[32]; 516 size_t i; 517 int fd; 518 519 /* 520 * Check if /dev/kcov is available, if not bail out. 521 * Verifying it on a per-thread basis is flaky. 522 */ 523 fd = open_kcov(); 524 ATF_REQUIRE(close(fd) == 0); 525 526 ATF_REQUIRE(__arraycount(thread) >= N); 527 528 for (i = 0; i < N; i++) 529 pthread_create(&thread[i], NULL, multiple_threads_helper, NULL); 530 531 for (i = 0; i < N; i++) 532 pthread_join(thread[i], NULL); 533 } 534 535 #define KCOV_MULTIPLE_THREADS(n) \ 536 ATF_TC_WITHOUT_HEAD(kcov_multiple_threads##n); \ 537 ATF_TC_BODY(kcov_multiple_threads##n, tc) \ 538 { \ 539 \ 540 kcov_multiple_threads(n); \ 541 } 542 543 KCOV_MULTIPLE_THREADS(2) 544 KCOV_MULTIPLE_THREADS(4) 545 KCOV_MULTIPLE_THREADS(8) 546 KCOV_MULTIPLE_THREADS(16) 547 KCOV_MULTIPLE_THREADS(32) 548 549 ATF_TP_ADD_TCS(tp) 550 { 551 552 ATF_TP_ADD_TC(tp, kcov_dup2); 553 ATF_TP_ADD_TC(tp, kcov_multiopen); 554 ATF_TP_ADD_TC(tp, kcov_open_close_open); 555 ATF_TP_ADD_TC(tp, kcov_bufsize); 556 ATF_TP_ADD_TC(tp, kcov_mmap); 557 ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap); 558 ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap_no_close); 559 ATF_TP_ADD_TC(tp, kcov_enable); 560 ATF_TP_ADD_TC(tp, kcov_enable_no_disable); 561 ATF_TP_ADD_TC(tp, kcov_enable_no_disable_no_close); 562 ATF_TP_ADD_TC(tp, kcov_mmap_enable_thread_close); 563 ATF_TP_ADD_TC(tp, kcov_basic_pc); 564 ATF_TP_ADD_TC(tp, kcov_basic_cmp); 565 ATF_TP_ADD_TC(tp, kcov_basic_dup2_pc); 566 ATF_TP_ADD_TC(tp, kcov_basic_dup2_cmp); 567 ATF_TP_ADD_TC(tp, kcov_multienable_on_the_same_thread); 568 ATF_TP_ADD_TC(tp, kcov_buffer_access_from_custom_thread); 569 ATF_TP_ADD_TC(tp, kcov_thread); 570 ATF_TP_ADD_TC(tp, kcov_multiple_threads2); 571 ATF_TP_ADD_TC(tp, kcov_multiple_threads4); 572 ATF_TP_ADD_TC(tp, kcov_multiple_threads8); 573 ATF_TP_ADD_TC(tp, kcov_multiple_threads16); 574 ATF_TP_ADD_TC(tp, kcov_multiple_threads32); 575 return atf_no_error(); 576 } 577