1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <assert.h> 4 #include <fcntl.h> 5 #include <inttypes.h> 6 #include <libgen.h> 7 #include <limits.h> 8 #include <linux/coredump.h> 9 #include <linux/fs.h> 10 #include <linux/limits.h> 11 #include <pthread.h> 12 #include <string.h> 13 #include <sys/mount.h> 14 #include <poll.h> 15 #include <sys/epoll.h> 16 #include <sys/resource.h> 17 #include <sys/stat.h> 18 #include <sys/socket.h> 19 #include <sys/un.h> 20 #include <unistd.h> 21 22 #include "../kselftest_harness.h" 23 #include "../filesystems/wrappers.h" 24 #include "../pidfd/pidfd.h" 25 26 #define STACKDUMP_FILE "stack_values" 27 #define STACKDUMP_SCRIPT "stackdump" 28 #define NUM_THREAD_SPAWN 128 29 30 #ifndef PAGE_SIZE 31 #define PAGE_SIZE 4096 32 #endif 33 34 static void *do_nothing(void *) 35 { 36 while (1) 37 pause(); 38 39 return NULL; 40 } 41 42 static void crashing_child(void) 43 { 44 pthread_t thread; 45 int i; 46 47 for (i = 0; i < NUM_THREAD_SPAWN; ++i) 48 pthread_create(&thread, NULL, do_nothing, NULL); 49 50 /* crash on purpose */ 51 i = *(int *)NULL; 52 } 53 54 FIXTURE(coredump) 55 { 56 char original_core_pattern[256]; 57 pid_t pid_coredump_server; 58 int fd_tmpfs_detached; 59 }; 60 61 static int create_detached_tmpfs(void) 62 { 63 int fd_context, fd_tmpfs; 64 65 fd_context = sys_fsopen("tmpfs", 0); 66 if (fd_context < 0) 67 return -1; 68 69 if (sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0) 70 return -1; 71 72 fd_tmpfs = sys_fsmount(fd_context, 0, 0); 73 close(fd_context); 74 return fd_tmpfs; 75 } 76 77 FIXTURE_SETUP(coredump) 78 { 79 FILE *file; 80 int ret; 81 82 self->pid_coredump_server = -ESRCH; 83 self->fd_tmpfs_detached = -1; 84 file = fopen("/proc/sys/kernel/core_pattern", "r"); 85 ASSERT_NE(NULL, file); 86 87 ret = fread(self->original_core_pattern, 1, sizeof(self->original_core_pattern), file); 88 ASSERT_TRUE(ret || feof(file)); 89 ASSERT_LT(ret, sizeof(self->original_core_pattern)); 90 91 self->original_core_pattern[ret] = '\0'; 92 self->fd_tmpfs_detached = create_detached_tmpfs(); 93 ASSERT_GE(self->fd_tmpfs_detached, 0); 94 95 ret = fclose(file); 96 ASSERT_EQ(0, ret); 97 } 98 99 FIXTURE_TEARDOWN(coredump) 100 { 101 const char *reason; 102 FILE *file; 103 int ret, status; 104 105 unlink(STACKDUMP_FILE); 106 107 if (self->pid_coredump_server > 0) { 108 kill(self->pid_coredump_server, SIGTERM); 109 waitpid(self->pid_coredump_server, &status, 0); 110 } 111 unlink("/tmp/coredump.file"); 112 unlink("/tmp/coredump.socket"); 113 114 file = fopen("/proc/sys/kernel/core_pattern", "w"); 115 if (!file) { 116 reason = "Unable to open core_pattern"; 117 goto fail; 118 } 119 120 ret = fprintf(file, "%s", self->original_core_pattern); 121 if (ret < 0) { 122 reason = "Unable to write to core_pattern"; 123 goto fail; 124 } 125 126 ret = fclose(file); 127 if (ret) { 128 reason = "Unable to close core_pattern"; 129 goto fail; 130 } 131 132 if (self->fd_tmpfs_detached >= 0) { 133 ret = close(self->fd_tmpfs_detached); 134 if (ret < 0) { 135 reason = "Unable to close detached tmpfs"; 136 goto fail; 137 } 138 self->fd_tmpfs_detached = -1; 139 } 140 141 return; 142 fail: 143 /* This should never happen */ 144 fprintf(stderr, "Failed to cleanup stackdump test: %s\n", reason); 145 } 146 147 TEST_F_TIMEOUT(coredump, stackdump, 120) 148 { 149 unsigned long long stack; 150 char *test_dir, *line; 151 size_t line_length; 152 char buf[PAGE_SIZE]; 153 int ret, i, status; 154 FILE *file; 155 pid_t pid; 156 157 /* 158 * Step 1: Setup core_pattern so that the stackdump script is executed when the child 159 * process crashes 160 */ 161 ret = readlink("/proc/self/exe", buf, sizeof(buf)); 162 ASSERT_NE(-1, ret); 163 ASSERT_LT(ret, sizeof(buf)); 164 buf[ret] = '\0'; 165 166 test_dir = dirname(buf); 167 168 file = fopen("/proc/sys/kernel/core_pattern", "w"); 169 ASSERT_NE(NULL, file); 170 171 ret = fprintf(file, "|%1$s/%2$s %%P %1$s/%3$s", test_dir, STACKDUMP_SCRIPT, STACKDUMP_FILE); 172 ASSERT_LT(0, ret); 173 174 ret = fclose(file); 175 ASSERT_EQ(0, ret); 176 177 /* Step 2: Create a process who spawns some threads then crashes */ 178 pid = fork(); 179 ASSERT_TRUE(pid >= 0); 180 if (pid == 0) 181 crashing_child(); 182 183 /* 184 * Step 3: Wait for the stackdump script to write the stack pointers to the stackdump file 185 */ 186 waitpid(pid, &status, 0); 187 ASSERT_TRUE(WIFSIGNALED(status)); 188 ASSERT_TRUE(WCOREDUMP(status)); 189 190 for (i = 0; i < 10; ++i) { 191 file = fopen(STACKDUMP_FILE, "r"); 192 if (file) 193 break; 194 sleep(1); 195 } 196 ASSERT_NE(file, NULL); 197 198 /* Step 4: Make sure all stack pointer values are non-zero */ 199 line = NULL; 200 for (i = 0; -1 != getline(&line, &line_length, file); ++i) { 201 stack = strtoull(line, NULL, 10); 202 ASSERT_NE(stack, 0); 203 } 204 free(line); 205 206 ASSERT_EQ(i, 1 + NUM_THREAD_SPAWN); 207 208 fclose(file); 209 } 210 211 static int create_and_listen_unix_socket(const char *path) 212 { 213 struct sockaddr_un addr = { 214 .sun_family = AF_UNIX, 215 }; 216 assert(strlen(path) < sizeof(addr.sun_path) - 1); 217 strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); 218 size_t addr_len = 219 offsetof(struct sockaddr_un, sun_path) + strlen(path) + 1; 220 int fd, ret; 221 222 fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); 223 if (fd < 0) 224 goto out; 225 226 ret = bind(fd, (const struct sockaddr *)&addr, addr_len); 227 if (ret < 0) 228 goto out; 229 230 ret = listen(fd, 128); 231 if (ret < 0) 232 goto out; 233 234 return fd; 235 236 out: 237 if (fd >= 0) 238 close(fd); 239 return -1; 240 } 241 242 static bool set_core_pattern(const char *pattern) 243 { 244 int fd; 245 ssize_t ret; 246 247 fd = open("/proc/sys/kernel/core_pattern", O_WRONLY | O_CLOEXEC); 248 if (fd < 0) 249 return false; 250 251 ret = write(fd, pattern, strlen(pattern)); 252 close(fd); 253 if (ret < 0) 254 return false; 255 256 fprintf(stderr, "Set core_pattern to '%s' | %zu == %zu\n", pattern, ret, strlen(pattern)); 257 return ret == strlen(pattern); 258 } 259 260 static int get_peer_pidfd(int fd) 261 { 262 int fd_peer_pidfd; 263 socklen_t fd_peer_pidfd_len = sizeof(fd_peer_pidfd); 264 int ret = getsockopt(fd, SOL_SOCKET, SO_PEERPIDFD, &fd_peer_pidfd, 265 &fd_peer_pidfd_len); 266 if (ret < 0) { 267 fprintf(stderr, "%m - Failed to retrieve peer pidfd for coredump socket connection\n"); 268 return -1; 269 } 270 return fd_peer_pidfd; 271 } 272 273 static bool get_pidfd_info(int fd_peer_pidfd, struct pidfd_info *info) 274 { 275 memset(info, 0, sizeof(*info)); 276 info->mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP; 277 return ioctl(fd_peer_pidfd, PIDFD_GET_INFO, info) == 0; 278 } 279 280 static void 281 wait_and_check_coredump_server(pid_t pid_coredump_server, 282 struct __test_metadata *const _metadata, 283 FIXTURE_DATA(coredump)* self) 284 { 285 int status; 286 waitpid(pid_coredump_server, &status, 0); 287 self->pid_coredump_server = -ESRCH; 288 ASSERT_TRUE(WIFEXITED(status)); 289 ASSERT_EQ(WEXITSTATUS(status), 0); 290 } 291 292 TEST_F(coredump, socket) 293 { 294 int pidfd, ret, status; 295 pid_t pid, pid_coredump_server; 296 struct stat st; 297 struct pidfd_info info = {}; 298 int ipc_sockets[2]; 299 char c; 300 301 ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket")); 302 303 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 304 ASSERT_EQ(ret, 0); 305 306 pid_coredump_server = fork(); 307 ASSERT_GE(pid_coredump_server, 0); 308 if (pid_coredump_server == 0) { 309 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1; 310 int exit_code = EXIT_FAILURE; 311 312 close(ipc_sockets[0]); 313 314 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 315 if (fd_server < 0) 316 goto out; 317 318 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 319 goto out; 320 321 close(ipc_sockets[1]); 322 323 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 324 if (fd_coredump < 0) 325 goto out; 326 327 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 328 if (fd_peer_pidfd < 0) 329 goto out; 330 331 if (!get_pidfd_info(fd_peer_pidfd, &info)) 332 goto out; 333 334 if (!(info.mask & PIDFD_INFO_COREDUMP)) 335 goto out; 336 337 if (!(info.coredump_mask & PIDFD_COREDUMPED)) 338 goto out; 339 340 fd_core_file = creat("/tmp/coredump.file", 0644); 341 if (fd_core_file < 0) 342 goto out; 343 344 for (;;) { 345 char buffer[4096]; 346 ssize_t bytes_read, bytes_write; 347 348 bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 349 if (bytes_read < 0) 350 goto out; 351 352 if (bytes_read == 0) 353 break; 354 355 bytes_write = write(fd_core_file, buffer, bytes_read); 356 if (bytes_read != bytes_write) 357 goto out; 358 } 359 360 exit_code = EXIT_SUCCESS; 361 out: 362 if (fd_core_file >= 0) 363 close(fd_core_file); 364 if (fd_peer_pidfd >= 0) 365 close(fd_peer_pidfd); 366 if (fd_coredump >= 0) 367 close(fd_coredump); 368 if (fd_server >= 0) 369 close(fd_server); 370 _exit(exit_code); 371 } 372 self->pid_coredump_server = pid_coredump_server; 373 374 EXPECT_EQ(close(ipc_sockets[1]), 0); 375 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 376 EXPECT_EQ(close(ipc_sockets[0]), 0); 377 378 pid = fork(); 379 ASSERT_GE(pid, 0); 380 if (pid == 0) 381 crashing_child(); 382 383 pidfd = sys_pidfd_open(pid, 0); 384 ASSERT_GE(pidfd, 0); 385 386 waitpid(pid, &status, 0); 387 ASSERT_TRUE(WIFSIGNALED(status)); 388 ASSERT_TRUE(WCOREDUMP(status)); 389 390 ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 391 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 392 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 393 394 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 395 396 ASSERT_EQ(stat("/tmp/coredump.file", &st), 0); 397 ASSERT_GT(st.st_size, 0); 398 system("file /tmp/coredump.file"); 399 } 400 401 TEST_F(coredump, socket_detect_userspace_client) 402 { 403 int pidfd, ret, status; 404 pid_t pid, pid_coredump_server; 405 struct stat st; 406 struct pidfd_info info = {}; 407 int ipc_sockets[2]; 408 char c; 409 410 ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket")); 411 412 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 413 ASSERT_EQ(ret, 0); 414 415 pid_coredump_server = fork(); 416 ASSERT_GE(pid_coredump_server, 0); 417 if (pid_coredump_server == 0) { 418 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 419 int exit_code = EXIT_FAILURE; 420 421 close(ipc_sockets[0]); 422 423 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 424 if (fd_server < 0) 425 goto out; 426 427 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 428 goto out; 429 430 close(ipc_sockets[1]); 431 432 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 433 if (fd_coredump < 0) 434 goto out; 435 436 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 437 if (fd_peer_pidfd < 0) 438 goto out; 439 440 if (!get_pidfd_info(fd_peer_pidfd, &info)) 441 goto out; 442 443 if (!(info.mask & PIDFD_INFO_COREDUMP)) 444 goto out; 445 446 if (info.coredump_mask & PIDFD_COREDUMPED) 447 goto out; 448 449 exit_code = EXIT_SUCCESS; 450 out: 451 if (fd_peer_pidfd >= 0) 452 close(fd_peer_pidfd); 453 if (fd_coredump >= 0) 454 close(fd_coredump); 455 if (fd_server >= 0) 456 close(fd_server); 457 _exit(exit_code); 458 } 459 self->pid_coredump_server = pid_coredump_server; 460 461 EXPECT_EQ(close(ipc_sockets[1]), 0); 462 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 463 EXPECT_EQ(close(ipc_sockets[0]), 0); 464 465 pid = fork(); 466 ASSERT_GE(pid, 0); 467 if (pid == 0) { 468 int fd_socket; 469 ssize_t ret; 470 const struct sockaddr_un coredump_sk = { 471 .sun_family = AF_UNIX, 472 .sun_path = "/tmp/coredump.socket", 473 }; 474 size_t coredump_sk_len = 475 offsetof(struct sockaddr_un, sun_path) + 476 sizeof("/tmp/coredump.socket"); 477 478 fd_socket = socket(AF_UNIX, SOCK_STREAM, 0); 479 if (fd_socket < 0) 480 _exit(EXIT_FAILURE); 481 482 ret = connect(fd_socket, (const struct sockaddr *)&coredump_sk, coredump_sk_len); 483 if (ret < 0) 484 _exit(EXIT_FAILURE); 485 486 close(fd_socket); 487 _exit(EXIT_SUCCESS); 488 } 489 490 pidfd = sys_pidfd_open(pid, 0); 491 ASSERT_GE(pidfd, 0); 492 493 waitpid(pid, &status, 0); 494 ASSERT_TRUE(WIFEXITED(status)); 495 ASSERT_EQ(WEXITSTATUS(status), 0); 496 497 ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 498 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 499 ASSERT_EQ((info.coredump_mask & PIDFD_COREDUMPED), 0); 500 501 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 502 503 ASSERT_NE(stat("/tmp/coredump.file", &st), 0); 504 ASSERT_EQ(errno, ENOENT); 505 } 506 507 TEST_F(coredump, socket_enoent) 508 { 509 int pidfd, status; 510 pid_t pid; 511 512 ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket")); 513 514 pid = fork(); 515 ASSERT_GE(pid, 0); 516 if (pid == 0) 517 crashing_child(); 518 519 pidfd = sys_pidfd_open(pid, 0); 520 ASSERT_GE(pidfd, 0); 521 522 waitpid(pid, &status, 0); 523 ASSERT_TRUE(WIFSIGNALED(status)); 524 ASSERT_FALSE(WCOREDUMP(status)); 525 } 526 527 TEST_F(coredump, socket_no_listener) 528 { 529 int pidfd, ret, status; 530 pid_t pid, pid_coredump_server; 531 int ipc_sockets[2]; 532 char c; 533 const struct sockaddr_un coredump_sk = { 534 .sun_family = AF_UNIX, 535 .sun_path = "/tmp/coredump.socket", 536 }; 537 size_t coredump_sk_len = offsetof(struct sockaddr_un, sun_path) + 538 sizeof("/tmp/coredump.socket"); 539 540 ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket")); 541 542 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 543 ASSERT_EQ(ret, 0); 544 545 pid_coredump_server = fork(); 546 ASSERT_GE(pid_coredump_server, 0); 547 if (pid_coredump_server == 0) { 548 int fd_server = -1; 549 int exit_code = EXIT_FAILURE; 550 551 close(ipc_sockets[0]); 552 553 fd_server = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); 554 if (fd_server < 0) 555 goto out; 556 557 ret = bind(fd_server, (const struct sockaddr *)&coredump_sk, coredump_sk_len); 558 if (ret < 0) 559 goto out; 560 561 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 562 goto out; 563 564 exit_code = EXIT_SUCCESS; 565 out: 566 if (fd_server >= 0) 567 close(fd_server); 568 close(ipc_sockets[1]); 569 _exit(exit_code); 570 } 571 self->pid_coredump_server = pid_coredump_server; 572 573 EXPECT_EQ(close(ipc_sockets[1]), 0); 574 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 575 EXPECT_EQ(close(ipc_sockets[0]), 0); 576 577 pid = fork(); 578 ASSERT_GE(pid, 0); 579 if (pid == 0) 580 crashing_child(); 581 582 pidfd = sys_pidfd_open(pid, 0); 583 ASSERT_GE(pidfd, 0); 584 585 waitpid(pid, &status, 0); 586 ASSERT_TRUE(WIFSIGNALED(status)); 587 ASSERT_FALSE(WCOREDUMP(status)); 588 589 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 590 } 591 592 static ssize_t recv_marker(int fd) 593 { 594 enum coredump_mark mark = COREDUMP_MARK_REQACK; 595 ssize_t ret; 596 597 ret = recv(fd, &mark, sizeof(mark), MSG_WAITALL); 598 if (ret != sizeof(mark)) 599 return -1; 600 601 switch (mark) { 602 case COREDUMP_MARK_REQACK: 603 fprintf(stderr, "Received marker: ReqAck\n"); 604 return COREDUMP_MARK_REQACK; 605 case COREDUMP_MARK_MINSIZE: 606 fprintf(stderr, "Received marker: MinSize\n"); 607 return COREDUMP_MARK_MINSIZE; 608 case COREDUMP_MARK_MAXSIZE: 609 fprintf(stderr, "Received marker: MaxSize\n"); 610 return COREDUMP_MARK_MAXSIZE; 611 case COREDUMP_MARK_UNSUPPORTED: 612 fprintf(stderr, "Received marker: Unsupported\n"); 613 return COREDUMP_MARK_UNSUPPORTED; 614 case COREDUMP_MARK_CONFLICTING: 615 fprintf(stderr, "Received marker: Conflicting\n"); 616 return COREDUMP_MARK_CONFLICTING; 617 default: 618 fprintf(stderr, "Received unknown marker: %u\n", mark); 619 break; 620 } 621 return -1; 622 } 623 624 static bool read_marker(int fd, enum coredump_mark mark) 625 { 626 ssize_t ret; 627 628 ret = recv_marker(fd); 629 if (ret < 0) 630 return false; 631 return ret == mark; 632 } 633 634 static bool read_coredump_req(int fd, struct coredump_req *req) 635 { 636 ssize_t ret; 637 size_t field_size, user_size, ack_size, kernel_size, remaining_size; 638 639 memset(req, 0, sizeof(*req)); 640 field_size = sizeof(req->size); 641 642 /* Peek the size of the coredump request. */ 643 ret = recv(fd, req, field_size, MSG_PEEK | MSG_WAITALL); 644 if (ret != field_size) 645 return false; 646 kernel_size = req->size; 647 648 if (kernel_size < COREDUMP_ACK_SIZE_VER0) 649 return false; 650 if (kernel_size >= PAGE_SIZE) 651 return false; 652 653 /* Use the minimum of user and kernel size to read the full request. */ 654 user_size = sizeof(struct coredump_req); 655 ack_size = user_size < kernel_size ? user_size : kernel_size; 656 ret = recv(fd, req, ack_size, MSG_WAITALL); 657 if (ret != ack_size) 658 return false; 659 660 fprintf(stderr, "Read coredump request with size %u and mask 0x%llx\n", 661 req->size, (unsigned long long)req->mask); 662 663 if (user_size > kernel_size) 664 remaining_size = user_size - kernel_size; 665 else 666 remaining_size = kernel_size - user_size; 667 668 if (PAGE_SIZE <= remaining_size) 669 return false; 670 671 /* 672 * Discard any additional data if the kernel's request was larger than 673 * what we knew about or cared about. 674 */ 675 if (remaining_size) { 676 char buffer[PAGE_SIZE]; 677 678 ret = recv(fd, buffer, sizeof(buffer), MSG_WAITALL); 679 if (ret != remaining_size) 680 return false; 681 fprintf(stderr, "Discarded %zu bytes of data after coredump request\n", remaining_size); 682 } 683 684 return true; 685 } 686 687 static bool send_coredump_ack(int fd, const struct coredump_req *req, 688 __u64 mask, size_t size_ack) 689 { 690 ssize_t ret; 691 /* 692 * Wrap struct coredump_ack in a larger struct so we can 693 * simulate sending to much data to the kernel. 694 */ 695 struct large_ack_for_size_testing { 696 struct coredump_ack ack; 697 char buffer[PAGE_SIZE]; 698 } large_ack = {}; 699 700 if (!size_ack) 701 size_ack = sizeof(struct coredump_ack) < req->size_ack ? 702 sizeof(struct coredump_ack) : 703 req->size_ack; 704 large_ack.ack.mask = mask; 705 large_ack.ack.size = size_ack; 706 ret = send(fd, &large_ack, size_ack, MSG_NOSIGNAL); 707 if (ret != size_ack) 708 return false; 709 710 fprintf(stderr, "Sent coredump ack with size %zu and mask 0x%llx\n", 711 size_ack, (unsigned long long)mask); 712 return true; 713 } 714 715 static bool check_coredump_req(const struct coredump_req *req, size_t min_size, 716 __u64 required_mask) 717 { 718 if (req->size < min_size) 719 return false; 720 if ((req->mask & required_mask) != required_mask) 721 return false; 722 if (req->mask & ~required_mask) 723 return false; 724 return true; 725 } 726 727 TEST_F(coredump, socket_request_kernel) 728 { 729 int pidfd, ret, status; 730 pid_t pid, pid_coredump_server; 731 struct stat st; 732 struct pidfd_info info = {}; 733 int ipc_sockets[2]; 734 char c; 735 736 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 737 738 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 739 ASSERT_EQ(ret, 0); 740 741 pid_coredump_server = fork(); 742 ASSERT_GE(pid_coredump_server, 0); 743 if (pid_coredump_server == 0) { 744 struct coredump_req req = {}; 745 int fd_server = -1, fd_coredump = -1, fd_core_file = -1, fd_peer_pidfd = -1; 746 int exit_code = EXIT_FAILURE; 747 748 close(ipc_sockets[0]); 749 750 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 751 if (fd_server < 0) 752 goto out; 753 754 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 755 goto out; 756 757 close(ipc_sockets[1]); 758 759 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 760 if (fd_coredump < 0) 761 goto out; 762 763 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 764 if (fd_peer_pidfd < 0) 765 goto out; 766 767 if (!get_pidfd_info(fd_peer_pidfd, &info)) 768 goto out; 769 770 if (!(info.mask & PIDFD_INFO_COREDUMP)) 771 goto out; 772 773 if (!(info.coredump_mask & PIDFD_COREDUMPED)) 774 goto out; 775 776 fd_core_file = creat("/tmp/coredump.file", 0644); 777 if (fd_core_file < 0) 778 goto out; 779 780 if (!read_coredump_req(fd_coredump, &req)) 781 goto out; 782 783 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 784 COREDUMP_KERNEL | COREDUMP_USERSPACE | 785 COREDUMP_REJECT | COREDUMP_WAIT)) 786 goto out; 787 788 if (!send_coredump_ack(fd_coredump, &req, 789 COREDUMP_KERNEL | COREDUMP_WAIT, 0)) 790 goto out; 791 792 if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) 793 goto out; 794 795 for (;;) { 796 char buffer[4096]; 797 ssize_t bytes_read, bytes_write; 798 799 bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 800 if (bytes_read < 0) 801 goto out; 802 803 if (bytes_read == 0) 804 break; 805 806 bytes_write = write(fd_core_file, buffer, bytes_read); 807 if (bytes_read != bytes_write) 808 goto out; 809 } 810 811 exit_code = EXIT_SUCCESS; 812 out: 813 if (fd_core_file >= 0) 814 close(fd_core_file); 815 if (fd_peer_pidfd >= 0) 816 close(fd_peer_pidfd); 817 if (fd_coredump >= 0) 818 close(fd_coredump); 819 if (fd_server >= 0) 820 close(fd_server); 821 _exit(exit_code); 822 } 823 self->pid_coredump_server = pid_coredump_server; 824 825 EXPECT_EQ(close(ipc_sockets[1]), 0); 826 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 827 EXPECT_EQ(close(ipc_sockets[0]), 0); 828 829 pid = fork(); 830 ASSERT_GE(pid, 0); 831 if (pid == 0) 832 crashing_child(); 833 834 pidfd = sys_pidfd_open(pid, 0); 835 ASSERT_GE(pidfd, 0); 836 837 waitpid(pid, &status, 0); 838 ASSERT_TRUE(WIFSIGNALED(status)); 839 ASSERT_TRUE(WCOREDUMP(status)); 840 841 ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 842 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 843 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 844 845 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 846 847 ASSERT_EQ(stat("/tmp/coredump.file", &st), 0); 848 ASSERT_GT(st.st_size, 0); 849 system("file /tmp/coredump.file"); 850 } 851 852 TEST_F(coredump, socket_request_userspace) 853 { 854 int pidfd, ret, status; 855 pid_t pid, pid_coredump_server; 856 struct pidfd_info info = {}; 857 int ipc_sockets[2]; 858 char c; 859 860 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 861 862 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 863 ASSERT_EQ(ret, 0); 864 865 pid_coredump_server = fork(); 866 ASSERT_GE(pid_coredump_server, 0); 867 if (pid_coredump_server == 0) { 868 struct coredump_req req = {}; 869 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 870 int exit_code = EXIT_FAILURE; 871 872 close(ipc_sockets[0]); 873 874 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 875 if (fd_server < 0) 876 goto out; 877 878 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 879 goto out; 880 881 close(ipc_sockets[1]); 882 883 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 884 if (fd_coredump < 0) 885 goto out; 886 887 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 888 if (fd_peer_pidfd < 0) 889 goto out; 890 891 if (!get_pidfd_info(fd_peer_pidfd, &info)) 892 goto out; 893 894 if (!(info.mask & PIDFD_INFO_COREDUMP)) 895 goto out; 896 897 if (!(info.coredump_mask & PIDFD_COREDUMPED)) 898 goto out; 899 900 if (!read_coredump_req(fd_coredump, &req)) 901 goto out; 902 903 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 904 COREDUMP_KERNEL | COREDUMP_USERSPACE | 905 COREDUMP_REJECT | COREDUMP_WAIT)) 906 goto out; 907 908 if (!send_coredump_ack(fd_coredump, &req, 909 COREDUMP_USERSPACE | COREDUMP_WAIT, 0)) 910 goto out; 911 912 if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) 913 goto out; 914 915 for (;;) { 916 char buffer[4096]; 917 ssize_t bytes_read; 918 919 bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 920 if (bytes_read > 0) 921 goto out; 922 923 if (bytes_read < 0) 924 goto out; 925 926 if (bytes_read == 0) 927 break; 928 } 929 930 exit_code = EXIT_SUCCESS; 931 out: 932 if (fd_peer_pidfd >= 0) 933 close(fd_peer_pidfd); 934 if (fd_coredump >= 0) 935 close(fd_coredump); 936 if (fd_server >= 0) 937 close(fd_server); 938 _exit(exit_code); 939 } 940 self->pid_coredump_server = pid_coredump_server; 941 942 EXPECT_EQ(close(ipc_sockets[1]), 0); 943 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 944 EXPECT_EQ(close(ipc_sockets[0]), 0); 945 946 pid = fork(); 947 ASSERT_GE(pid, 0); 948 if (pid == 0) 949 crashing_child(); 950 951 pidfd = sys_pidfd_open(pid, 0); 952 ASSERT_GE(pidfd, 0); 953 954 waitpid(pid, &status, 0); 955 ASSERT_TRUE(WIFSIGNALED(status)); 956 ASSERT_TRUE(WCOREDUMP(status)); 957 958 ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 959 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 960 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 961 962 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 963 } 964 965 TEST_F(coredump, socket_request_reject) 966 { 967 int pidfd, ret, status; 968 pid_t pid, pid_coredump_server; 969 struct pidfd_info info = {}; 970 int ipc_sockets[2]; 971 char c; 972 973 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 974 975 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 976 ASSERT_EQ(ret, 0); 977 978 pid_coredump_server = fork(); 979 ASSERT_GE(pid_coredump_server, 0); 980 if (pid_coredump_server == 0) { 981 struct coredump_req req = {}; 982 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 983 int exit_code = EXIT_FAILURE; 984 985 close(ipc_sockets[0]); 986 987 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 988 if (fd_server < 0) 989 goto out; 990 991 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 992 goto out; 993 994 close(ipc_sockets[1]); 995 996 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 997 if (fd_coredump < 0) 998 goto out; 999 1000 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1001 if (fd_peer_pidfd < 0) 1002 goto out; 1003 1004 if (!get_pidfd_info(fd_peer_pidfd, &info)) 1005 goto out; 1006 1007 if (!(info.mask & PIDFD_INFO_COREDUMP)) 1008 goto out; 1009 1010 if (!(info.coredump_mask & PIDFD_COREDUMPED)) 1011 goto out; 1012 1013 if (!read_coredump_req(fd_coredump, &req)) 1014 goto out; 1015 1016 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1017 COREDUMP_KERNEL | COREDUMP_USERSPACE | 1018 COREDUMP_REJECT | COREDUMP_WAIT)) 1019 goto out; 1020 1021 if (!send_coredump_ack(fd_coredump, &req, 1022 COREDUMP_REJECT | COREDUMP_WAIT, 0)) 1023 goto out; 1024 1025 if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) 1026 goto out; 1027 1028 for (;;) { 1029 char buffer[4096]; 1030 ssize_t bytes_read; 1031 1032 bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 1033 if (bytes_read > 0) 1034 goto out; 1035 1036 if (bytes_read < 0) 1037 goto out; 1038 1039 if (bytes_read == 0) 1040 break; 1041 } 1042 1043 exit_code = EXIT_SUCCESS; 1044 out: 1045 if (fd_peer_pidfd >= 0) 1046 close(fd_peer_pidfd); 1047 if (fd_coredump >= 0) 1048 close(fd_coredump); 1049 if (fd_server >= 0) 1050 close(fd_server); 1051 _exit(exit_code); 1052 } 1053 self->pid_coredump_server = pid_coredump_server; 1054 1055 EXPECT_EQ(close(ipc_sockets[1]), 0); 1056 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1057 EXPECT_EQ(close(ipc_sockets[0]), 0); 1058 1059 pid = fork(); 1060 ASSERT_GE(pid, 0); 1061 if (pid == 0) 1062 crashing_child(); 1063 1064 pidfd = sys_pidfd_open(pid, 0); 1065 ASSERT_GE(pidfd, 0); 1066 1067 waitpid(pid, &status, 0); 1068 ASSERT_TRUE(WIFSIGNALED(status)); 1069 ASSERT_FALSE(WCOREDUMP(status)); 1070 1071 ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 1072 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1073 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1074 1075 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1076 } 1077 1078 TEST_F(coredump, socket_request_invalid_flag_combination) 1079 { 1080 int pidfd, ret, status; 1081 pid_t pid, pid_coredump_server; 1082 struct pidfd_info info = {}; 1083 int ipc_sockets[2]; 1084 char c; 1085 1086 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1087 1088 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 1089 ASSERT_EQ(ret, 0); 1090 1091 pid_coredump_server = fork(); 1092 ASSERT_GE(pid_coredump_server, 0); 1093 if (pid_coredump_server == 0) { 1094 struct coredump_req req = {}; 1095 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 1096 int exit_code = EXIT_FAILURE; 1097 1098 close(ipc_sockets[0]); 1099 1100 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1101 if (fd_server < 0) 1102 goto out; 1103 1104 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 1105 goto out; 1106 1107 close(ipc_sockets[1]); 1108 1109 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1110 if (fd_coredump < 0) 1111 goto out; 1112 1113 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1114 if (fd_peer_pidfd < 0) 1115 goto out; 1116 1117 if (!get_pidfd_info(fd_peer_pidfd, &info)) 1118 goto out; 1119 1120 if (!(info.mask & PIDFD_INFO_COREDUMP)) 1121 goto out; 1122 1123 if (!(info.coredump_mask & PIDFD_COREDUMPED)) 1124 goto out; 1125 1126 if (!read_coredump_req(fd_coredump, &req)) 1127 goto out; 1128 1129 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1130 COREDUMP_KERNEL | COREDUMP_USERSPACE | 1131 COREDUMP_REJECT | COREDUMP_WAIT)) 1132 goto out; 1133 1134 if (!send_coredump_ack(fd_coredump, &req, 1135 COREDUMP_KERNEL | COREDUMP_REJECT | COREDUMP_WAIT, 0)) 1136 goto out; 1137 1138 if (!read_marker(fd_coredump, COREDUMP_MARK_CONFLICTING)) 1139 goto out; 1140 1141 exit_code = EXIT_SUCCESS; 1142 out: 1143 if (fd_peer_pidfd >= 0) 1144 close(fd_peer_pidfd); 1145 if (fd_coredump >= 0) 1146 close(fd_coredump); 1147 if (fd_server >= 0) 1148 close(fd_server); 1149 _exit(exit_code); 1150 } 1151 self->pid_coredump_server = pid_coredump_server; 1152 1153 EXPECT_EQ(close(ipc_sockets[1]), 0); 1154 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1155 EXPECT_EQ(close(ipc_sockets[0]), 0); 1156 1157 pid = fork(); 1158 ASSERT_GE(pid, 0); 1159 if (pid == 0) 1160 crashing_child(); 1161 1162 pidfd = sys_pidfd_open(pid, 0); 1163 ASSERT_GE(pidfd, 0); 1164 1165 waitpid(pid, &status, 0); 1166 ASSERT_TRUE(WIFSIGNALED(status)); 1167 ASSERT_FALSE(WCOREDUMP(status)); 1168 1169 ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 1170 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1171 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1172 1173 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1174 } 1175 1176 TEST_F(coredump, socket_request_unknown_flag) 1177 { 1178 int pidfd, ret, status; 1179 pid_t pid, pid_coredump_server; 1180 struct pidfd_info info = {}; 1181 int ipc_sockets[2]; 1182 char c; 1183 1184 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1185 1186 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 1187 ASSERT_EQ(ret, 0); 1188 1189 pid_coredump_server = fork(); 1190 ASSERT_GE(pid_coredump_server, 0); 1191 if (pid_coredump_server == 0) { 1192 struct coredump_req req = {}; 1193 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 1194 int exit_code = EXIT_FAILURE; 1195 1196 close(ipc_sockets[0]); 1197 1198 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1199 if (fd_server < 0) 1200 goto out; 1201 1202 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 1203 goto out; 1204 1205 close(ipc_sockets[1]); 1206 1207 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1208 if (fd_coredump < 0) 1209 goto out; 1210 1211 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1212 if (fd_peer_pidfd < 0) 1213 goto out; 1214 1215 if (!get_pidfd_info(fd_peer_pidfd, &info)) 1216 goto out; 1217 1218 if (!(info.mask & PIDFD_INFO_COREDUMP)) 1219 goto out; 1220 1221 if (!(info.coredump_mask & PIDFD_COREDUMPED)) 1222 goto out; 1223 1224 if (!read_coredump_req(fd_coredump, &req)) 1225 goto out; 1226 1227 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1228 COREDUMP_KERNEL | COREDUMP_USERSPACE | 1229 COREDUMP_REJECT | COREDUMP_WAIT)) 1230 goto out; 1231 1232 if (!send_coredump_ack(fd_coredump, &req, (1ULL << 63), 0)) 1233 goto out; 1234 1235 if (!read_marker(fd_coredump, COREDUMP_MARK_UNSUPPORTED)) 1236 goto out; 1237 1238 exit_code = EXIT_SUCCESS; 1239 out: 1240 if (fd_peer_pidfd >= 0) 1241 close(fd_peer_pidfd); 1242 if (fd_coredump >= 0) 1243 close(fd_coredump); 1244 if (fd_server >= 0) 1245 close(fd_server); 1246 _exit(exit_code); 1247 } 1248 self->pid_coredump_server = pid_coredump_server; 1249 1250 EXPECT_EQ(close(ipc_sockets[1]), 0); 1251 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1252 EXPECT_EQ(close(ipc_sockets[0]), 0); 1253 1254 pid = fork(); 1255 ASSERT_GE(pid, 0); 1256 if (pid == 0) 1257 crashing_child(); 1258 1259 pidfd = sys_pidfd_open(pid, 0); 1260 ASSERT_GE(pidfd, 0); 1261 1262 waitpid(pid, &status, 0); 1263 ASSERT_TRUE(WIFSIGNALED(status)); 1264 ASSERT_FALSE(WCOREDUMP(status)); 1265 1266 ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 1267 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1268 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1269 1270 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1271 } 1272 1273 TEST_F(coredump, socket_request_invalid_size_small) 1274 { 1275 int pidfd, ret, status; 1276 pid_t pid, pid_coredump_server; 1277 struct pidfd_info info = {}; 1278 int ipc_sockets[2]; 1279 char c; 1280 1281 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1282 1283 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 1284 ASSERT_EQ(ret, 0); 1285 1286 pid_coredump_server = fork(); 1287 ASSERT_GE(pid_coredump_server, 0); 1288 if (pid_coredump_server == 0) { 1289 struct coredump_req req = {}; 1290 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 1291 int exit_code = EXIT_FAILURE; 1292 1293 close(ipc_sockets[0]); 1294 1295 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1296 if (fd_server < 0) 1297 goto out; 1298 1299 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 1300 goto out; 1301 1302 close(ipc_sockets[1]); 1303 1304 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1305 if (fd_coredump < 0) 1306 goto out; 1307 1308 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1309 if (fd_peer_pidfd < 0) 1310 goto out; 1311 1312 if (!get_pidfd_info(fd_peer_pidfd, &info)) 1313 goto out; 1314 1315 if (!(info.mask & PIDFD_INFO_COREDUMP)) 1316 goto out; 1317 1318 if (!(info.coredump_mask & PIDFD_COREDUMPED)) 1319 goto out; 1320 1321 if (!read_coredump_req(fd_coredump, &req)) 1322 goto out; 1323 1324 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1325 COREDUMP_KERNEL | COREDUMP_USERSPACE | 1326 COREDUMP_REJECT | COREDUMP_WAIT)) 1327 goto out; 1328 1329 if (!send_coredump_ack(fd_coredump, &req, 1330 COREDUMP_REJECT | COREDUMP_WAIT, 1331 COREDUMP_ACK_SIZE_VER0 / 2)) 1332 goto out; 1333 1334 if (!read_marker(fd_coredump, COREDUMP_MARK_MINSIZE)) 1335 goto out; 1336 1337 exit_code = EXIT_SUCCESS; 1338 out: 1339 if (fd_peer_pidfd >= 0) 1340 close(fd_peer_pidfd); 1341 if (fd_coredump >= 0) 1342 close(fd_coredump); 1343 if (fd_server >= 0) 1344 close(fd_server); 1345 _exit(exit_code); 1346 } 1347 self->pid_coredump_server = pid_coredump_server; 1348 1349 EXPECT_EQ(close(ipc_sockets[1]), 0); 1350 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1351 EXPECT_EQ(close(ipc_sockets[0]), 0); 1352 1353 pid = fork(); 1354 ASSERT_GE(pid, 0); 1355 if (pid == 0) 1356 crashing_child(); 1357 1358 pidfd = sys_pidfd_open(pid, 0); 1359 ASSERT_GE(pidfd, 0); 1360 1361 waitpid(pid, &status, 0); 1362 ASSERT_TRUE(WIFSIGNALED(status)); 1363 ASSERT_FALSE(WCOREDUMP(status)); 1364 1365 ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 1366 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1367 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1368 1369 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1370 } 1371 1372 TEST_F(coredump, socket_request_invalid_size_large) 1373 { 1374 int pidfd, ret, status; 1375 pid_t pid, pid_coredump_server; 1376 struct pidfd_info info = {}; 1377 int ipc_sockets[2]; 1378 char c; 1379 1380 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1381 1382 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 1383 ASSERT_EQ(ret, 0); 1384 1385 pid_coredump_server = fork(); 1386 ASSERT_GE(pid_coredump_server, 0); 1387 if (pid_coredump_server == 0) { 1388 struct coredump_req req = {}; 1389 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 1390 int exit_code = EXIT_FAILURE; 1391 1392 close(ipc_sockets[0]); 1393 1394 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1395 if (fd_server < 0) 1396 goto out; 1397 1398 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 1399 goto out; 1400 1401 close(ipc_sockets[1]); 1402 1403 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1404 if (fd_coredump < 0) 1405 goto out; 1406 1407 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1408 if (fd_peer_pidfd < 0) 1409 goto out; 1410 1411 if (!get_pidfd_info(fd_peer_pidfd, &info)) 1412 goto out; 1413 1414 if (!(info.mask & PIDFD_INFO_COREDUMP)) 1415 goto out; 1416 1417 if (!(info.coredump_mask & PIDFD_COREDUMPED)) 1418 goto out; 1419 1420 if (!read_coredump_req(fd_coredump, &req)) 1421 goto out; 1422 1423 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1424 COREDUMP_KERNEL | COREDUMP_USERSPACE | 1425 COREDUMP_REJECT | COREDUMP_WAIT)) 1426 goto out; 1427 1428 if (!send_coredump_ack(fd_coredump, &req, 1429 COREDUMP_REJECT | COREDUMP_WAIT, 1430 COREDUMP_ACK_SIZE_VER0 + PAGE_SIZE)) 1431 goto out; 1432 1433 if (!read_marker(fd_coredump, COREDUMP_MARK_MAXSIZE)) 1434 goto out; 1435 1436 exit_code = EXIT_SUCCESS; 1437 out: 1438 if (fd_peer_pidfd >= 0) 1439 close(fd_peer_pidfd); 1440 if (fd_coredump >= 0) 1441 close(fd_coredump); 1442 if (fd_server >= 0) 1443 close(fd_server); 1444 _exit(exit_code); 1445 } 1446 self->pid_coredump_server = pid_coredump_server; 1447 1448 EXPECT_EQ(close(ipc_sockets[1]), 0); 1449 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1450 EXPECT_EQ(close(ipc_sockets[0]), 0); 1451 1452 pid = fork(); 1453 ASSERT_GE(pid, 0); 1454 if (pid == 0) 1455 crashing_child(); 1456 1457 pidfd = sys_pidfd_open(pid, 0); 1458 ASSERT_GE(pidfd, 0); 1459 1460 waitpid(pid, &status, 0); 1461 ASSERT_TRUE(WIFSIGNALED(status)); 1462 ASSERT_FALSE(WCOREDUMP(status)); 1463 1464 ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 1465 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1466 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1467 1468 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1469 } 1470 1471 static int open_coredump_tmpfile(int fd_tmpfs_detached) 1472 { 1473 return openat(fd_tmpfs_detached, ".", O_TMPFILE | O_RDWR | O_EXCL, 0600); 1474 } 1475 1476 #define NUM_CRASHING_COREDUMPS 5 1477 1478 TEST_F_TIMEOUT(coredump, socket_multiple_crashing_coredumps, 500) 1479 { 1480 int pidfd[NUM_CRASHING_COREDUMPS], status[NUM_CRASHING_COREDUMPS]; 1481 pid_t pid[NUM_CRASHING_COREDUMPS], pid_coredump_server; 1482 struct pidfd_info info = {}; 1483 int ipc_sockets[2]; 1484 char c; 1485 1486 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1487 1488 ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets), 0); 1489 1490 pid_coredump_server = fork(); 1491 ASSERT_GE(pid_coredump_server, 0); 1492 if (pid_coredump_server == 0) { 1493 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1; 1494 int exit_code = EXIT_FAILURE; 1495 struct coredump_req req = {}; 1496 1497 close(ipc_sockets[0]); 1498 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1499 if (fd_server < 0) { 1500 fprintf(stderr, "Failed to create and listen on unix socket\n"); 1501 goto out; 1502 } 1503 1504 if (write_nointr(ipc_sockets[1], "1", 1) < 0) { 1505 fprintf(stderr, "Failed to notify parent via ipc socket\n"); 1506 goto out; 1507 } 1508 close(ipc_sockets[1]); 1509 1510 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1511 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1512 if (fd_coredump < 0) { 1513 fprintf(stderr, "accept4 failed: %m\n"); 1514 goto out; 1515 } 1516 1517 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1518 if (fd_peer_pidfd < 0) { 1519 fprintf(stderr, "get_peer_pidfd failed for fd %d: %m\n", fd_coredump); 1520 goto out; 1521 } 1522 1523 if (!get_pidfd_info(fd_peer_pidfd, &info)) { 1524 fprintf(stderr, "get_pidfd_info failed for fd %d\n", fd_peer_pidfd); 1525 goto out; 1526 } 1527 1528 if (!(info.mask & PIDFD_INFO_COREDUMP)) { 1529 fprintf(stderr, "pidfd info missing PIDFD_INFO_COREDUMP for fd %d\n", fd_peer_pidfd); 1530 goto out; 1531 } 1532 if (!(info.coredump_mask & PIDFD_COREDUMPED)) { 1533 fprintf(stderr, "pidfd info missing PIDFD_COREDUMPED for fd %d\n", fd_peer_pidfd); 1534 goto out; 1535 } 1536 1537 if (!read_coredump_req(fd_coredump, &req)) { 1538 fprintf(stderr, "read_coredump_req failed for fd %d\n", fd_coredump); 1539 goto out; 1540 } 1541 1542 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1543 COREDUMP_KERNEL | COREDUMP_USERSPACE | 1544 COREDUMP_REJECT | COREDUMP_WAIT)) { 1545 fprintf(stderr, "check_coredump_req failed for fd %d\n", fd_coredump); 1546 goto out; 1547 } 1548 1549 if (!send_coredump_ack(fd_coredump, &req, 1550 COREDUMP_KERNEL | COREDUMP_WAIT, 0)) { 1551 fprintf(stderr, "send_coredump_ack failed for fd %d\n", fd_coredump); 1552 goto out; 1553 } 1554 1555 if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) { 1556 fprintf(stderr, "read_marker failed for fd %d\n", fd_coredump); 1557 goto out; 1558 } 1559 1560 fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached); 1561 if (fd_core_file < 0) { 1562 fprintf(stderr, "%m - open_coredump_tmpfile failed for fd %d\n", fd_coredump); 1563 goto out; 1564 } 1565 1566 for (;;) { 1567 char buffer[4096]; 1568 ssize_t bytes_read, bytes_write; 1569 1570 bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 1571 if (bytes_read < 0) { 1572 fprintf(stderr, "read failed for fd %d: %m\n", fd_coredump); 1573 goto out; 1574 } 1575 1576 if (bytes_read == 0) 1577 break; 1578 1579 bytes_write = write(fd_core_file, buffer, bytes_read); 1580 if (bytes_read != bytes_write) { 1581 fprintf(stderr, "write failed for fd %d: %m\n", fd_core_file); 1582 goto out; 1583 } 1584 } 1585 1586 close(fd_core_file); 1587 close(fd_peer_pidfd); 1588 close(fd_coredump); 1589 fd_peer_pidfd = -1; 1590 fd_coredump = -1; 1591 } 1592 1593 exit_code = EXIT_SUCCESS; 1594 out: 1595 if (fd_core_file >= 0) 1596 close(fd_core_file); 1597 if (fd_peer_pidfd >= 0) 1598 close(fd_peer_pidfd); 1599 if (fd_coredump >= 0) 1600 close(fd_coredump); 1601 if (fd_server >= 0) 1602 close(fd_server); 1603 _exit(exit_code); 1604 } 1605 self->pid_coredump_server = pid_coredump_server; 1606 1607 EXPECT_EQ(close(ipc_sockets[1]), 0); 1608 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1609 EXPECT_EQ(close(ipc_sockets[0]), 0); 1610 1611 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1612 pid[i] = fork(); 1613 ASSERT_GE(pid[i], 0); 1614 if (pid[i] == 0) 1615 crashing_child(); 1616 pidfd[i] = sys_pidfd_open(pid[i], 0); 1617 ASSERT_GE(pidfd[i], 0); 1618 } 1619 1620 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1621 waitpid(pid[i], &status[i], 0); 1622 ASSERT_TRUE(WIFSIGNALED(status[i])); 1623 ASSERT_TRUE(WCOREDUMP(status[i])); 1624 } 1625 1626 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1627 info.mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP; 1628 ASSERT_EQ(ioctl(pidfd[i], PIDFD_GET_INFO, &info), 0); 1629 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1630 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1631 } 1632 1633 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1634 } 1635 1636 #define MAX_EVENTS 128 1637 1638 static void process_coredump_worker(int fd_coredump, int fd_peer_pidfd, int fd_core_file) 1639 { 1640 int epfd = -1; 1641 int exit_code = EXIT_FAILURE; 1642 1643 epfd = epoll_create1(0); 1644 if (epfd < 0) 1645 goto out; 1646 1647 struct epoll_event ev; 1648 ev.events = EPOLLIN | EPOLLRDHUP | EPOLLET; 1649 ev.data.fd = fd_coredump; 1650 if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd_coredump, &ev) < 0) 1651 goto out; 1652 1653 for (;;) { 1654 struct epoll_event events[1]; 1655 int n = epoll_wait(epfd, events, 1, -1); 1656 if (n < 0) 1657 break; 1658 1659 if (events[0].events & (EPOLLIN | EPOLLRDHUP)) { 1660 for (;;) { 1661 char buffer[4096]; 1662 ssize_t bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 1663 if (bytes_read < 0) { 1664 if (errno == EAGAIN || errno == EWOULDBLOCK) 1665 break; 1666 goto out; 1667 } 1668 if (bytes_read == 0) 1669 goto done; 1670 ssize_t bytes_write = write(fd_core_file, buffer, bytes_read); 1671 if (bytes_write != bytes_read) 1672 goto out; 1673 } 1674 } 1675 } 1676 1677 done: 1678 exit_code = EXIT_SUCCESS; 1679 out: 1680 if (epfd >= 0) 1681 close(epfd); 1682 if (fd_core_file >= 0) 1683 close(fd_core_file); 1684 if (fd_peer_pidfd >= 0) 1685 close(fd_peer_pidfd); 1686 if (fd_coredump >= 0) 1687 close(fd_coredump); 1688 _exit(exit_code); 1689 } 1690 1691 TEST_F_TIMEOUT(coredump, socket_multiple_crashing_coredumps_epoll_workers, 500) 1692 { 1693 int pidfd[NUM_CRASHING_COREDUMPS], status[NUM_CRASHING_COREDUMPS]; 1694 pid_t pid[NUM_CRASHING_COREDUMPS], pid_coredump_server, worker_pids[NUM_CRASHING_COREDUMPS]; 1695 struct pidfd_info info = {}; 1696 int ipc_sockets[2]; 1697 char c; 1698 1699 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1700 ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets), 0); 1701 1702 pid_coredump_server = fork(); 1703 ASSERT_GE(pid_coredump_server, 0); 1704 if (pid_coredump_server == 0) { 1705 int fd_server = -1, exit_code = EXIT_FAILURE, n_conns = 0; 1706 fd_server = -1; 1707 exit_code = EXIT_FAILURE; 1708 n_conns = 0; 1709 close(ipc_sockets[0]); 1710 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1711 if (fd_server < 0) 1712 goto out; 1713 1714 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 1715 goto out; 1716 close(ipc_sockets[1]); 1717 1718 while (n_conns < NUM_CRASHING_COREDUMPS) { 1719 int fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1; 1720 struct coredump_req req = {}; 1721 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1722 if (fd_coredump < 0) { 1723 if (errno == EAGAIN || errno == EWOULDBLOCK) 1724 continue; 1725 goto out; 1726 } 1727 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1728 if (fd_peer_pidfd < 0) 1729 goto out; 1730 if (!get_pidfd_info(fd_peer_pidfd, &info)) 1731 goto out; 1732 if (!(info.mask & PIDFD_INFO_COREDUMP) || !(info.coredump_mask & PIDFD_COREDUMPED)) 1733 goto out; 1734 if (!read_coredump_req(fd_coredump, &req)) 1735 goto out; 1736 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1737 COREDUMP_KERNEL | COREDUMP_USERSPACE | 1738 COREDUMP_REJECT | COREDUMP_WAIT)) 1739 goto out; 1740 if (!send_coredump_ack(fd_coredump, &req, COREDUMP_KERNEL | COREDUMP_WAIT, 0)) 1741 goto out; 1742 if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) 1743 goto out; 1744 fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached); 1745 if (fd_core_file < 0) 1746 goto out; 1747 pid_t worker = fork(); 1748 if (worker == 0) { 1749 close(fd_server); 1750 process_coredump_worker(fd_coredump, fd_peer_pidfd, fd_core_file); 1751 } 1752 worker_pids[n_conns] = worker; 1753 if (fd_coredump >= 0) 1754 close(fd_coredump); 1755 if (fd_peer_pidfd >= 0) 1756 close(fd_peer_pidfd); 1757 if (fd_core_file >= 0) 1758 close(fd_core_file); 1759 n_conns++; 1760 } 1761 exit_code = EXIT_SUCCESS; 1762 out: 1763 if (fd_server >= 0) 1764 close(fd_server); 1765 1766 // Reap all worker processes 1767 for (int i = 0; i < n_conns; i++) { 1768 int wstatus; 1769 if (waitpid(worker_pids[i], &wstatus, 0) < 0) { 1770 fprintf(stderr, "Failed to wait for worker %d: %m\n", worker_pids[i]); 1771 } else if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != EXIT_SUCCESS) { 1772 fprintf(stderr, "Worker %d exited with error code %d\n", worker_pids[i], WEXITSTATUS(wstatus)); 1773 exit_code = EXIT_FAILURE; 1774 } 1775 } 1776 1777 _exit(exit_code); 1778 } 1779 self->pid_coredump_server = pid_coredump_server; 1780 1781 EXPECT_EQ(close(ipc_sockets[1]), 0); 1782 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1783 EXPECT_EQ(close(ipc_sockets[0]), 0); 1784 1785 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1786 pid[i] = fork(); 1787 ASSERT_GE(pid[i], 0); 1788 if (pid[i] == 0) 1789 crashing_child(); 1790 pidfd[i] = sys_pidfd_open(pid[i], 0); 1791 ASSERT_GE(pidfd[i], 0); 1792 } 1793 1794 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1795 ASSERT_GE(waitpid(pid[i], &status[i], 0), 0); 1796 ASSERT_TRUE(WIFSIGNALED(status[i])); 1797 ASSERT_TRUE(WCOREDUMP(status[i])); 1798 } 1799 1800 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1801 info.mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP; 1802 ASSERT_EQ(ioctl(pidfd[i], PIDFD_GET_INFO, &info), 0); 1803 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1804 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1805 } 1806 1807 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1808 } 1809 1810 TEST_F(coredump, socket_invalid_paths) 1811 { 1812 ASSERT_FALSE(set_core_pattern("@ /tmp/coredump.socket")); 1813 ASSERT_FALSE(set_core_pattern("@/tmp/../coredump.socket")); 1814 ASSERT_FALSE(set_core_pattern("@../coredump.socket")); 1815 ASSERT_FALSE(set_core_pattern("@/tmp/coredump.socket/..")); 1816 ASSERT_FALSE(set_core_pattern("@..")); 1817 1818 ASSERT_FALSE(set_core_pattern("@@ /tmp/coredump.socket")); 1819 ASSERT_FALSE(set_core_pattern("@@/tmp/../coredump.socket")); 1820 ASSERT_FALSE(set_core_pattern("@@../coredump.socket")); 1821 ASSERT_FALSE(set_core_pattern("@@/tmp/coredump.socket/..")); 1822 ASSERT_FALSE(set_core_pattern("@@..")); 1823 1824 ASSERT_FALSE(set_core_pattern("@@@/tmp/coredump.socket")); 1825 } 1826 1827 TEST_HARNESS_MAIN 1828