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 if (read(fd_coredump, &c, 1) < 1) 450 goto out; 451 452 exit_code = EXIT_SUCCESS; 453 out: 454 if (fd_peer_pidfd >= 0) 455 close(fd_peer_pidfd); 456 if (fd_coredump >= 0) 457 close(fd_coredump); 458 if (fd_server >= 0) 459 close(fd_server); 460 _exit(exit_code); 461 } 462 self->pid_coredump_server = pid_coredump_server; 463 464 EXPECT_EQ(close(ipc_sockets[1]), 0); 465 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 466 EXPECT_EQ(close(ipc_sockets[0]), 0); 467 468 pid = fork(); 469 ASSERT_GE(pid, 0); 470 if (pid == 0) { 471 int fd_socket; 472 ssize_t ret; 473 const struct sockaddr_un coredump_sk = { 474 .sun_family = AF_UNIX, 475 .sun_path = "/tmp/coredump.socket", 476 }; 477 size_t coredump_sk_len = 478 offsetof(struct sockaddr_un, sun_path) + 479 sizeof("/tmp/coredump.socket"); 480 481 fd_socket = socket(AF_UNIX, SOCK_STREAM, 0); 482 if (fd_socket < 0) 483 _exit(EXIT_FAILURE); 484 485 ret = connect(fd_socket, (const struct sockaddr *)&coredump_sk, coredump_sk_len); 486 if (ret < 0) 487 _exit(EXIT_FAILURE); 488 489 close(fd_socket); 490 _exit(EXIT_SUCCESS); 491 } 492 493 pidfd = sys_pidfd_open(pid, 0); 494 ASSERT_GE(pidfd, 0); 495 496 waitpid(pid, &status, 0); 497 ASSERT_TRUE(WIFEXITED(status)); 498 ASSERT_EQ(WEXITSTATUS(status), 0); 499 500 ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 501 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 502 ASSERT_EQ((info.coredump_mask & PIDFD_COREDUMPED), 0); 503 504 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 505 506 ASSERT_NE(stat("/tmp/coredump.file", &st), 0); 507 ASSERT_EQ(errno, ENOENT); 508 } 509 510 TEST_F(coredump, socket_enoent) 511 { 512 int pidfd, status; 513 pid_t pid; 514 515 ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket")); 516 517 pid = fork(); 518 ASSERT_GE(pid, 0); 519 if (pid == 0) 520 crashing_child(); 521 522 pidfd = sys_pidfd_open(pid, 0); 523 ASSERT_GE(pidfd, 0); 524 525 waitpid(pid, &status, 0); 526 ASSERT_TRUE(WIFSIGNALED(status)); 527 ASSERT_FALSE(WCOREDUMP(status)); 528 } 529 530 TEST_F(coredump, socket_no_listener) 531 { 532 int pidfd, ret, status; 533 pid_t pid, pid_coredump_server; 534 int ipc_sockets[2]; 535 char c; 536 const struct sockaddr_un coredump_sk = { 537 .sun_family = AF_UNIX, 538 .sun_path = "/tmp/coredump.socket", 539 }; 540 size_t coredump_sk_len = offsetof(struct sockaddr_un, sun_path) + 541 sizeof("/tmp/coredump.socket"); 542 543 ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket")); 544 545 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 546 ASSERT_EQ(ret, 0); 547 548 pid_coredump_server = fork(); 549 ASSERT_GE(pid_coredump_server, 0); 550 if (pid_coredump_server == 0) { 551 int fd_server = -1; 552 int exit_code = EXIT_FAILURE; 553 554 close(ipc_sockets[0]); 555 556 fd_server = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); 557 if (fd_server < 0) 558 goto out; 559 560 ret = bind(fd_server, (const struct sockaddr *)&coredump_sk, coredump_sk_len); 561 if (ret < 0) 562 goto out; 563 564 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 565 goto out; 566 567 exit_code = EXIT_SUCCESS; 568 out: 569 if (fd_server >= 0) 570 close(fd_server); 571 close(ipc_sockets[1]); 572 _exit(exit_code); 573 } 574 self->pid_coredump_server = pid_coredump_server; 575 576 EXPECT_EQ(close(ipc_sockets[1]), 0); 577 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 578 EXPECT_EQ(close(ipc_sockets[0]), 0); 579 580 pid = fork(); 581 ASSERT_GE(pid, 0); 582 if (pid == 0) 583 crashing_child(); 584 585 pidfd = sys_pidfd_open(pid, 0); 586 ASSERT_GE(pidfd, 0); 587 588 waitpid(pid, &status, 0); 589 ASSERT_TRUE(WIFSIGNALED(status)); 590 ASSERT_FALSE(WCOREDUMP(status)); 591 592 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 593 } 594 595 static ssize_t recv_marker(int fd) 596 { 597 enum coredump_mark mark = COREDUMP_MARK_REQACK; 598 ssize_t ret; 599 600 ret = recv(fd, &mark, sizeof(mark), MSG_WAITALL); 601 if (ret != sizeof(mark)) 602 return -1; 603 604 switch (mark) { 605 case COREDUMP_MARK_REQACK: 606 fprintf(stderr, "Received marker: ReqAck\n"); 607 return COREDUMP_MARK_REQACK; 608 case COREDUMP_MARK_MINSIZE: 609 fprintf(stderr, "Received marker: MinSize\n"); 610 return COREDUMP_MARK_MINSIZE; 611 case COREDUMP_MARK_MAXSIZE: 612 fprintf(stderr, "Received marker: MaxSize\n"); 613 return COREDUMP_MARK_MAXSIZE; 614 case COREDUMP_MARK_UNSUPPORTED: 615 fprintf(stderr, "Received marker: Unsupported\n"); 616 return COREDUMP_MARK_UNSUPPORTED; 617 case COREDUMP_MARK_CONFLICTING: 618 fprintf(stderr, "Received marker: Conflicting\n"); 619 return COREDUMP_MARK_CONFLICTING; 620 default: 621 fprintf(stderr, "Received unknown marker: %u\n", mark); 622 break; 623 } 624 return -1; 625 } 626 627 static bool read_marker(int fd, enum coredump_mark mark) 628 { 629 ssize_t ret; 630 631 ret = recv_marker(fd); 632 if (ret < 0) 633 return false; 634 return ret == mark; 635 } 636 637 static bool read_coredump_req(int fd, struct coredump_req *req) 638 { 639 ssize_t ret; 640 size_t field_size, user_size, ack_size, kernel_size, remaining_size; 641 642 memset(req, 0, sizeof(*req)); 643 field_size = sizeof(req->size); 644 645 /* Peek the size of the coredump request. */ 646 ret = recv(fd, req, field_size, MSG_PEEK | MSG_WAITALL); 647 if (ret != field_size) 648 return false; 649 kernel_size = req->size; 650 651 if (kernel_size < COREDUMP_ACK_SIZE_VER0) 652 return false; 653 if (kernel_size >= PAGE_SIZE) 654 return false; 655 656 /* Use the minimum of user and kernel size to read the full request. */ 657 user_size = sizeof(struct coredump_req); 658 ack_size = user_size < kernel_size ? user_size : kernel_size; 659 ret = recv(fd, req, ack_size, MSG_WAITALL); 660 if (ret != ack_size) 661 return false; 662 663 fprintf(stderr, "Read coredump request with size %u and mask 0x%llx\n", 664 req->size, (unsigned long long)req->mask); 665 666 if (user_size > kernel_size) 667 remaining_size = user_size - kernel_size; 668 else 669 remaining_size = kernel_size - user_size; 670 671 if (PAGE_SIZE <= remaining_size) 672 return false; 673 674 /* 675 * Discard any additional data if the kernel's request was larger than 676 * what we knew about or cared about. 677 */ 678 if (remaining_size) { 679 char buffer[PAGE_SIZE]; 680 681 ret = recv(fd, buffer, sizeof(buffer), MSG_WAITALL); 682 if (ret != remaining_size) 683 return false; 684 fprintf(stderr, "Discarded %zu bytes of data after coredump request\n", remaining_size); 685 } 686 687 return true; 688 } 689 690 static bool send_coredump_ack(int fd, const struct coredump_req *req, 691 __u64 mask, size_t size_ack) 692 { 693 ssize_t ret; 694 /* 695 * Wrap struct coredump_ack in a larger struct so we can 696 * simulate sending to much data to the kernel. 697 */ 698 struct large_ack_for_size_testing { 699 struct coredump_ack ack; 700 char buffer[PAGE_SIZE]; 701 } large_ack = {}; 702 703 if (!size_ack) 704 size_ack = sizeof(struct coredump_ack) < req->size_ack ? 705 sizeof(struct coredump_ack) : 706 req->size_ack; 707 large_ack.ack.mask = mask; 708 large_ack.ack.size = size_ack; 709 ret = send(fd, &large_ack, size_ack, MSG_NOSIGNAL); 710 if (ret != size_ack) 711 return false; 712 713 fprintf(stderr, "Sent coredump ack with size %zu and mask 0x%llx\n", 714 size_ack, (unsigned long long)mask); 715 return true; 716 } 717 718 static bool check_coredump_req(const struct coredump_req *req, size_t min_size, 719 __u64 required_mask) 720 { 721 if (req->size < min_size) 722 return false; 723 if ((req->mask & required_mask) != required_mask) 724 return false; 725 if (req->mask & ~required_mask) 726 return false; 727 return true; 728 } 729 730 TEST_F(coredump, socket_request_kernel) 731 { 732 int pidfd, ret, status; 733 pid_t pid, pid_coredump_server; 734 struct stat st; 735 struct pidfd_info info = {}; 736 int ipc_sockets[2]; 737 char c; 738 739 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 740 741 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 742 ASSERT_EQ(ret, 0); 743 744 pid_coredump_server = fork(); 745 ASSERT_GE(pid_coredump_server, 0); 746 if (pid_coredump_server == 0) { 747 struct coredump_req req = {}; 748 int fd_server = -1, fd_coredump = -1, fd_core_file = -1, fd_peer_pidfd = -1; 749 int exit_code = EXIT_FAILURE; 750 751 close(ipc_sockets[0]); 752 753 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 754 if (fd_server < 0) 755 goto out; 756 757 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 758 goto out; 759 760 close(ipc_sockets[1]); 761 762 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 763 if (fd_coredump < 0) 764 goto out; 765 766 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 767 if (fd_peer_pidfd < 0) 768 goto out; 769 770 if (!get_pidfd_info(fd_peer_pidfd, &info)) 771 goto out; 772 773 if (!(info.mask & PIDFD_INFO_COREDUMP)) 774 goto out; 775 776 if (!(info.coredump_mask & PIDFD_COREDUMPED)) 777 goto out; 778 779 fd_core_file = creat("/tmp/coredump.file", 0644); 780 if (fd_core_file < 0) 781 goto out; 782 783 if (!read_coredump_req(fd_coredump, &req)) 784 goto out; 785 786 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 787 COREDUMP_KERNEL | COREDUMP_USERSPACE | 788 COREDUMP_REJECT | COREDUMP_WAIT)) 789 goto out; 790 791 if (!send_coredump_ack(fd_coredump, &req, 792 COREDUMP_KERNEL | COREDUMP_WAIT, 0)) 793 goto out; 794 795 if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) 796 goto out; 797 798 for (;;) { 799 char buffer[4096]; 800 ssize_t bytes_read, bytes_write; 801 802 bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 803 if (bytes_read < 0) 804 goto out; 805 806 if (bytes_read == 0) 807 break; 808 809 bytes_write = write(fd_core_file, buffer, bytes_read); 810 if (bytes_read != bytes_write) 811 goto out; 812 } 813 814 exit_code = EXIT_SUCCESS; 815 out: 816 if (fd_core_file >= 0) 817 close(fd_core_file); 818 if (fd_peer_pidfd >= 0) 819 close(fd_peer_pidfd); 820 if (fd_coredump >= 0) 821 close(fd_coredump); 822 if (fd_server >= 0) 823 close(fd_server); 824 _exit(exit_code); 825 } 826 self->pid_coredump_server = pid_coredump_server; 827 828 EXPECT_EQ(close(ipc_sockets[1]), 0); 829 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 830 EXPECT_EQ(close(ipc_sockets[0]), 0); 831 832 pid = fork(); 833 ASSERT_GE(pid, 0); 834 if (pid == 0) 835 crashing_child(); 836 837 pidfd = sys_pidfd_open(pid, 0); 838 ASSERT_GE(pidfd, 0); 839 840 waitpid(pid, &status, 0); 841 ASSERT_TRUE(WIFSIGNALED(status)); 842 ASSERT_TRUE(WCOREDUMP(status)); 843 844 ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 845 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 846 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 847 848 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 849 850 ASSERT_EQ(stat("/tmp/coredump.file", &st), 0); 851 ASSERT_GT(st.st_size, 0); 852 system("file /tmp/coredump.file"); 853 } 854 855 TEST_F(coredump, socket_request_userspace) 856 { 857 int pidfd, ret, status; 858 pid_t pid, pid_coredump_server; 859 struct pidfd_info info = {}; 860 int ipc_sockets[2]; 861 char c; 862 863 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 864 865 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 866 ASSERT_EQ(ret, 0); 867 868 pid_coredump_server = fork(); 869 ASSERT_GE(pid_coredump_server, 0); 870 if (pid_coredump_server == 0) { 871 struct coredump_req req = {}; 872 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 873 int exit_code = EXIT_FAILURE; 874 875 close(ipc_sockets[0]); 876 877 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 878 if (fd_server < 0) 879 goto out; 880 881 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 882 goto out; 883 884 close(ipc_sockets[1]); 885 886 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 887 if (fd_coredump < 0) 888 goto out; 889 890 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 891 if (fd_peer_pidfd < 0) 892 goto out; 893 894 if (!get_pidfd_info(fd_peer_pidfd, &info)) 895 goto out; 896 897 if (!(info.mask & PIDFD_INFO_COREDUMP)) 898 goto out; 899 900 if (!(info.coredump_mask & PIDFD_COREDUMPED)) 901 goto out; 902 903 if (!read_coredump_req(fd_coredump, &req)) 904 goto out; 905 906 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 907 COREDUMP_KERNEL | COREDUMP_USERSPACE | 908 COREDUMP_REJECT | COREDUMP_WAIT)) 909 goto out; 910 911 if (!send_coredump_ack(fd_coredump, &req, 912 COREDUMP_USERSPACE | COREDUMP_WAIT, 0)) 913 goto out; 914 915 if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) 916 goto out; 917 918 for (;;) { 919 char buffer[4096]; 920 ssize_t bytes_read; 921 922 bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 923 if (bytes_read > 0) 924 goto out; 925 926 if (bytes_read < 0) 927 goto out; 928 929 if (bytes_read == 0) 930 break; 931 } 932 933 exit_code = EXIT_SUCCESS; 934 out: 935 if (fd_peer_pidfd >= 0) 936 close(fd_peer_pidfd); 937 if (fd_coredump >= 0) 938 close(fd_coredump); 939 if (fd_server >= 0) 940 close(fd_server); 941 _exit(exit_code); 942 } 943 self->pid_coredump_server = pid_coredump_server; 944 945 EXPECT_EQ(close(ipc_sockets[1]), 0); 946 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 947 EXPECT_EQ(close(ipc_sockets[0]), 0); 948 949 pid = fork(); 950 ASSERT_GE(pid, 0); 951 if (pid == 0) 952 crashing_child(); 953 954 pidfd = sys_pidfd_open(pid, 0); 955 ASSERT_GE(pidfd, 0); 956 957 waitpid(pid, &status, 0); 958 ASSERT_TRUE(WIFSIGNALED(status)); 959 ASSERT_TRUE(WCOREDUMP(status)); 960 961 ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 962 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 963 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 964 965 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 966 } 967 968 TEST_F(coredump, socket_request_reject) 969 { 970 int pidfd, ret, status; 971 pid_t pid, pid_coredump_server; 972 struct pidfd_info info = {}; 973 int ipc_sockets[2]; 974 char c; 975 976 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 977 978 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 979 ASSERT_EQ(ret, 0); 980 981 pid_coredump_server = fork(); 982 ASSERT_GE(pid_coredump_server, 0); 983 if (pid_coredump_server == 0) { 984 struct coredump_req req = {}; 985 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 986 int exit_code = EXIT_FAILURE; 987 988 close(ipc_sockets[0]); 989 990 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 991 if (fd_server < 0) 992 goto out; 993 994 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 995 goto out; 996 997 close(ipc_sockets[1]); 998 999 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1000 if (fd_coredump < 0) 1001 goto out; 1002 1003 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1004 if (fd_peer_pidfd < 0) 1005 goto out; 1006 1007 if (!get_pidfd_info(fd_peer_pidfd, &info)) 1008 goto out; 1009 1010 if (!(info.mask & PIDFD_INFO_COREDUMP)) 1011 goto out; 1012 1013 if (!(info.coredump_mask & PIDFD_COREDUMPED)) 1014 goto out; 1015 1016 if (!read_coredump_req(fd_coredump, &req)) 1017 goto out; 1018 1019 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1020 COREDUMP_KERNEL | COREDUMP_USERSPACE | 1021 COREDUMP_REJECT | COREDUMP_WAIT)) 1022 goto out; 1023 1024 if (!send_coredump_ack(fd_coredump, &req, 1025 COREDUMP_REJECT | COREDUMP_WAIT, 0)) 1026 goto out; 1027 1028 if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) 1029 goto out; 1030 1031 for (;;) { 1032 char buffer[4096]; 1033 ssize_t bytes_read; 1034 1035 bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 1036 if (bytes_read > 0) 1037 goto out; 1038 1039 if (bytes_read < 0) 1040 goto out; 1041 1042 if (bytes_read == 0) 1043 break; 1044 } 1045 1046 exit_code = EXIT_SUCCESS; 1047 out: 1048 if (fd_peer_pidfd >= 0) 1049 close(fd_peer_pidfd); 1050 if (fd_coredump >= 0) 1051 close(fd_coredump); 1052 if (fd_server >= 0) 1053 close(fd_server); 1054 _exit(exit_code); 1055 } 1056 self->pid_coredump_server = pid_coredump_server; 1057 1058 EXPECT_EQ(close(ipc_sockets[1]), 0); 1059 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1060 EXPECT_EQ(close(ipc_sockets[0]), 0); 1061 1062 pid = fork(); 1063 ASSERT_GE(pid, 0); 1064 if (pid == 0) 1065 crashing_child(); 1066 1067 pidfd = sys_pidfd_open(pid, 0); 1068 ASSERT_GE(pidfd, 0); 1069 1070 waitpid(pid, &status, 0); 1071 ASSERT_TRUE(WIFSIGNALED(status)); 1072 ASSERT_FALSE(WCOREDUMP(status)); 1073 1074 ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 1075 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1076 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1077 1078 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1079 } 1080 1081 TEST_F(coredump, socket_request_invalid_flag_combination) 1082 { 1083 int pidfd, ret, status; 1084 pid_t pid, pid_coredump_server; 1085 struct pidfd_info info = {}; 1086 int ipc_sockets[2]; 1087 char c; 1088 1089 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1090 1091 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 1092 ASSERT_EQ(ret, 0); 1093 1094 pid_coredump_server = fork(); 1095 ASSERT_GE(pid_coredump_server, 0); 1096 if (pid_coredump_server == 0) { 1097 struct coredump_req req = {}; 1098 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 1099 int exit_code = EXIT_FAILURE; 1100 1101 close(ipc_sockets[0]); 1102 1103 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1104 if (fd_server < 0) 1105 goto out; 1106 1107 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 1108 goto out; 1109 1110 close(ipc_sockets[1]); 1111 1112 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1113 if (fd_coredump < 0) 1114 goto out; 1115 1116 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1117 if (fd_peer_pidfd < 0) 1118 goto out; 1119 1120 if (!get_pidfd_info(fd_peer_pidfd, &info)) 1121 goto out; 1122 1123 if (!(info.mask & PIDFD_INFO_COREDUMP)) 1124 goto out; 1125 1126 if (!(info.coredump_mask & PIDFD_COREDUMPED)) 1127 goto out; 1128 1129 if (!read_coredump_req(fd_coredump, &req)) 1130 goto out; 1131 1132 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1133 COREDUMP_KERNEL | COREDUMP_USERSPACE | 1134 COREDUMP_REJECT | COREDUMP_WAIT)) 1135 goto out; 1136 1137 if (!send_coredump_ack(fd_coredump, &req, 1138 COREDUMP_KERNEL | COREDUMP_REJECT | COREDUMP_WAIT, 0)) 1139 goto out; 1140 1141 if (!read_marker(fd_coredump, COREDUMP_MARK_CONFLICTING)) 1142 goto out; 1143 1144 exit_code = EXIT_SUCCESS; 1145 out: 1146 if (fd_peer_pidfd >= 0) 1147 close(fd_peer_pidfd); 1148 if (fd_coredump >= 0) 1149 close(fd_coredump); 1150 if (fd_server >= 0) 1151 close(fd_server); 1152 _exit(exit_code); 1153 } 1154 self->pid_coredump_server = pid_coredump_server; 1155 1156 EXPECT_EQ(close(ipc_sockets[1]), 0); 1157 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1158 EXPECT_EQ(close(ipc_sockets[0]), 0); 1159 1160 pid = fork(); 1161 ASSERT_GE(pid, 0); 1162 if (pid == 0) 1163 crashing_child(); 1164 1165 pidfd = sys_pidfd_open(pid, 0); 1166 ASSERT_GE(pidfd, 0); 1167 1168 waitpid(pid, &status, 0); 1169 ASSERT_TRUE(WIFSIGNALED(status)); 1170 ASSERT_FALSE(WCOREDUMP(status)); 1171 1172 ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 1173 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1174 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1175 1176 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1177 } 1178 1179 TEST_F(coredump, socket_request_unknown_flag) 1180 { 1181 int pidfd, ret, status; 1182 pid_t pid, pid_coredump_server; 1183 struct pidfd_info info = {}; 1184 int ipc_sockets[2]; 1185 char c; 1186 1187 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1188 1189 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 1190 ASSERT_EQ(ret, 0); 1191 1192 pid_coredump_server = fork(); 1193 ASSERT_GE(pid_coredump_server, 0); 1194 if (pid_coredump_server == 0) { 1195 struct coredump_req req = {}; 1196 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 1197 int exit_code = EXIT_FAILURE; 1198 1199 close(ipc_sockets[0]); 1200 1201 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1202 if (fd_server < 0) 1203 goto out; 1204 1205 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 1206 goto out; 1207 1208 close(ipc_sockets[1]); 1209 1210 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1211 if (fd_coredump < 0) 1212 goto out; 1213 1214 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1215 if (fd_peer_pidfd < 0) 1216 goto out; 1217 1218 if (!get_pidfd_info(fd_peer_pidfd, &info)) 1219 goto out; 1220 1221 if (!(info.mask & PIDFD_INFO_COREDUMP)) 1222 goto out; 1223 1224 if (!(info.coredump_mask & PIDFD_COREDUMPED)) 1225 goto out; 1226 1227 if (!read_coredump_req(fd_coredump, &req)) 1228 goto out; 1229 1230 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1231 COREDUMP_KERNEL | COREDUMP_USERSPACE | 1232 COREDUMP_REJECT | COREDUMP_WAIT)) 1233 goto out; 1234 1235 if (!send_coredump_ack(fd_coredump, &req, (1ULL << 63), 0)) 1236 goto out; 1237 1238 if (!read_marker(fd_coredump, COREDUMP_MARK_UNSUPPORTED)) 1239 goto out; 1240 1241 exit_code = EXIT_SUCCESS; 1242 out: 1243 if (fd_peer_pidfd >= 0) 1244 close(fd_peer_pidfd); 1245 if (fd_coredump >= 0) 1246 close(fd_coredump); 1247 if (fd_server >= 0) 1248 close(fd_server); 1249 _exit(exit_code); 1250 } 1251 self->pid_coredump_server = pid_coredump_server; 1252 1253 EXPECT_EQ(close(ipc_sockets[1]), 0); 1254 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1255 EXPECT_EQ(close(ipc_sockets[0]), 0); 1256 1257 pid = fork(); 1258 ASSERT_GE(pid, 0); 1259 if (pid == 0) 1260 crashing_child(); 1261 1262 pidfd = sys_pidfd_open(pid, 0); 1263 ASSERT_GE(pidfd, 0); 1264 1265 waitpid(pid, &status, 0); 1266 ASSERT_TRUE(WIFSIGNALED(status)); 1267 ASSERT_FALSE(WCOREDUMP(status)); 1268 1269 ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 1270 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1271 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1272 1273 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1274 } 1275 1276 TEST_F(coredump, socket_request_invalid_size_small) 1277 { 1278 int pidfd, ret, status; 1279 pid_t pid, pid_coredump_server; 1280 struct pidfd_info info = {}; 1281 int ipc_sockets[2]; 1282 char c; 1283 1284 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1285 1286 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 1287 ASSERT_EQ(ret, 0); 1288 1289 pid_coredump_server = fork(); 1290 ASSERT_GE(pid_coredump_server, 0); 1291 if (pid_coredump_server == 0) { 1292 struct coredump_req req = {}; 1293 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 1294 int exit_code = EXIT_FAILURE; 1295 1296 close(ipc_sockets[0]); 1297 1298 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1299 if (fd_server < 0) 1300 goto out; 1301 1302 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 1303 goto out; 1304 1305 close(ipc_sockets[1]); 1306 1307 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1308 if (fd_coredump < 0) 1309 goto out; 1310 1311 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1312 if (fd_peer_pidfd < 0) 1313 goto out; 1314 1315 if (!get_pidfd_info(fd_peer_pidfd, &info)) 1316 goto out; 1317 1318 if (!(info.mask & PIDFD_INFO_COREDUMP)) 1319 goto out; 1320 1321 if (!(info.coredump_mask & PIDFD_COREDUMPED)) 1322 goto out; 1323 1324 if (!read_coredump_req(fd_coredump, &req)) 1325 goto out; 1326 1327 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1328 COREDUMP_KERNEL | COREDUMP_USERSPACE | 1329 COREDUMP_REJECT | COREDUMP_WAIT)) 1330 goto out; 1331 1332 if (!send_coredump_ack(fd_coredump, &req, 1333 COREDUMP_REJECT | COREDUMP_WAIT, 1334 COREDUMP_ACK_SIZE_VER0 / 2)) 1335 goto out; 1336 1337 if (!read_marker(fd_coredump, COREDUMP_MARK_MINSIZE)) 1338 goto out; 1339 1340 exit_code = EXIT_SUCCESS; 1341 out: 1342 if (fd_peer_pidfd >= 0) 1343 close(fd_peer_pidfd); 1344 if (fd_coredump >= 0) 1345 close(fd_coredump); 1346 if (fd_server >= 0) 1347 close(fd_server); 1348 _exit(exit_code); 1349 } 1350 self->pid_coredump_server = pid_coredump_server; 1351 1352 EXPECT_EQ(close(ipc_sockets[1]), 0); 1353 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1354 EXPECT_EQ(close(ipc_sockets[0]), 0); 1355 1356 pid = fork(); 1357 ASSERT_GE(pid, 0); 1358 if (pid == 0) 1359 crashing_child(); 1360 1361 pidfd = sys_pidfd_open(pid, 0); 1362 ASSERT_GE(pidfd, 0); 1363 1364 waitpid(pid, &status, 0); 1365 ASSERT_TRUE(WIFSIGNALED(status)); 1366 ASSERT_FALSE(WCOREDUMP(status)); 1367 1368 ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 1369 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1370 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1371 1372 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1373 } 1374 1375 TEST_F(coredump, socket_request_invalid_size_large) 1376 { 1377 int pidfd, ret, status; 1378 pid_t pid, pid_coredump_server; 1379 struct pidfd_info info = {}; 1380 int ipc_sockets[2]; 1381 char c; 1382 1383 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1384 1385 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 1386 ASSERT_EQ(ret, 0); 1387 1388 pid_coredump_server = fork(); 1389 ASSERT_GE(pid_coredump_server, 0); 1390 if (pid_coredump_server == 0) { 1391 struct coredump_req req = {}; 1392 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 1393 int exit_code = EXIT_FAILURE; 1394 1395 close(ipc_sockets[0]); 1396 1397 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1398 if (fd_server < 0) 1399 goto out; 1400 1401 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 1402 goto out; 1403 1404 close(ipc_sockets[1]); 1405 1406 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1407 if (fd_coredump < 0) 1408 goto out; 1409 1410 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1411 if (fd_peer_pidfd < 0) 1412 goto out; 1413 1414 if (!get_pidfd_info(fd_peer_pidfd, &info)) 1415 goto out; 1416 1417 if (!(info.mask & PIDFD_INFO_COREDUMP)) 1418 goto out; 1419 1420 if (!(info.coredump_mask & PIDFD_COREDUMPED)) 1421 goto out; 1422 1423 if (!read_coredump_req(fd_coredump, &req)) 1424 goto out; 1425 1426 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1427 COREDUMP_KERNEL | COREDUMP_USERSPACE | 1428 COREDUMP_REJECT | COREDUMP_WAIT)) 1429 goto out; 1430 1431 if (!send_coredump_ack(fd_coredump, &req, 1432 COREDUMP_REJECT | COREDUMP_WAIT, 1433 COREDUMP_ACK_SIZE_VER0 + PAGE_SIZE)) 1434 goto out; 1435 1436 if (!read_marker(fd_coredump, COREDUMP_MARK_MAXSIZE)) 1437 goto out; 1438 1439 exit_code = EXIT_SUCCESS; 1440 out: 1441 if (fd_peer_pidfd >= 0) 1442 close(fd_peer_pidfd); 1443 if (fd_coredump >= 0) 1444 close(fd_coredump); 1445 if (fd_server >= 0) 1446 close(fd_server); 1447 _exit(exit_code); 1448 } 1449 self->pid_coredump_server = pid_coredump_server; 1450 1451 EXPECT_EQ(close(ipc_sockets[1]), 0); 1452 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1453 EXPECT_EQ(close(ipc_sockets[0]), 0); 1454 1455 pid = fork(); 1456 ASSERT_GE(pid, 0); 1457 if (pid == 0) 1458 crashing_child(); 1459 1460 pidfd = sys_pidfd_open(pid, 0); 1461 ASSERT_GE(pidfd, 0); 1462 1463 waitpid(pid, &status, 0); 1464 ASSERT_TRUE(WIFSIGNALED(status)); 1465 ASSERT_FALSE(WCOREDUMP(status)); 1466 1467 ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 1468 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1469 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1470 1471 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1472 } 1473 1474 static int open_coredump_tmpfile(int fd_tmpfs_detached) 1475 { 1476 return openat(fd_tmpfs_detached, ".", O_TMPFILE | O_RDWR | O_EXCL, 0600); 1477 } 1478 1479 #define NUM_CRASHING_COREDUMPS 5 1480 1481 TEST_F_TIMEOUT(coredump, socket_multiple_crashing_coredumps, 500) 1482 { 1483 int pidfd[NUM_CRASHING_COREDUMPS], status[NUM_CRASHING_COREDUMPS]; 1484 pid_t pid[NUM_CRASHING_COREDUMPS], pid_coredump_server; 1485 struct pidfd_info info = {}; 1486 int ipc_sockets[2]; 1487 char c; 1488 1489 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1490 1491 ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets), 0); 1492 1493 pid_coredump_server = fork(); 1494 ASSERT_GE(pid_coredump_server, 0); 1495 if (pid_coredump_server == 0) { 1496 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1; 1497 int exit_code = EXIT_FAILURE; 1498 struct coredump_req req = {}; 1499 1500 close(ipc_sockets[0]); 1501 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1502 if (fd_server < 0) { 1503 fprintf(stderr, "Failed to create and listen on unix socket\n"); 1504 goto out; 1505 } 1506 1507 if (write_nointr(ipc_sockets[1], "1", 1) < 0) { 1508 fprintf(stderr, "Failed to notify parent via ipc socket\n"); 1509 goto out; 1510 } 1511 close(ipc_sockets[1]); 1512 1513 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1514 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1515 if (fd_coredump < 0) { 1516 fprintf(stderr, "accept4 failed: %m\n"); 1517 goto out; 1518 } 1519 1520 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1521 if (fd_peer_pidfd < 0) { 1522 fprintf(stderr, "get_peer_pidfd failed for fd %d: %m\n", fd_coredump); 1523 goto out; 1524 } 1525 1526 if (!get_pidfd_info(fd_peer_pidfd, &info)) { 1527 fprintf(stderr, "get_pidfd_info failed for fd %d\n", fd_peer_pidfd); 1528 goto out; 1529 } 1530 1531 if (!(info.mask & PIDFD_INFO_COREDUMP)) { 1532 fprintf(stderr, "pidfd info missing PIDFD_INFO_COREDUMP for fd %d\n", fd_peer_pidfd); 1533 goto out; 1534 } 1535 if (!(info.coredump_mask & PIDFD_COREDUMPED)) { 1536 fprintf(stderr, "pidfd info missing PIDFD_COREDUMPED for fd %d\n", fd_peer_pidfd); 1537 goto out; 1538 } 1539 1540 if (!read_coredump_req(fd_coredump, &req)) { 1541 fprintf(stderr, "read_coredump_req failed for fd %d\n", fd_coredump); 1542 goto out; 1543 } 1544 1545 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1546 COREDUMP_KERNEL | COREDUMP_USERSPACE | 1547 COREDUMP_REJECT | COREDUMP_WAIT)) { 1548 fprintf(stderr, "check_coredump_req failed for fd %d\n", fd_coredump); 1549 goto out; 1550 } 1551 1552 if (!send_coredump_ack(fd_coredump, &req, 1553 COREDUMP_KERNEL | COREDUMP_WAIT, 0)) { 1554 fprintf(stderr, "send_coredump_ack failed for fd %d\n", fd_coredump); 1555 goto out; 1556 } 1557 1558 if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) { 1559 fprintf(stderr, "read_marker failed for fd %d\n", fd_coredump); 1560 goto out; 1561 } 1562 1563 fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached); 1564 if (fd_core_file < 0) { 1565 fprintf(stderr, "%m - open_coredump_tmpfile failed for fd %d\n", fd_coredump); 1566 goto out; 1567 } 1568 1569 for (;;) { 1570 char buffer[4096]; 1571 ssize_t bytes_read, bytes_write; 1572 1573 bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 1574 if (bytes_read < 0) { 1575 fprintf(stderr, "read failed for fd %d: %m\n", fd_coredump); 1576 goto out; 1577 } 1578 1579 if (bytes_read == 0) 1580 break; 1581 1582 bytes_write = write(fd_core_file, buffer, bytes_read); 1583 if (bytes_read != bytes_write) { 1584 fprintf(stderr, "write failed for fd %d: %m\n", fd_core_file); 1585 goto out; 1586 } 1587 } 1588 1589 close(fd_core_file); 1590 close(fd_peer_pidfd); 1591 close(fd_coredump); 1592 fd_peer_pidfd = -1; 1593 fd_coredump = -1; 1594 } 1595 1596 exit_code = EXIT_SUCCESS; 1597 out: 1598 if (fd_core_file >= 0) 1599 close(fd_core_file); 1600 if (fd_peer_pidfd >= 0) 1601 close(fd_peer_pidfd); 1602 if (fd_coredump >= 0) 1603 close(fd_coredump); 1604 if (fd_server >= 0) 1605 close(fd_server); 1606 _exit(exit_code); 1607 } 1608 self->pid_coredump_server = pid_coredump_server; 1609 1610 EXPECT_EQ(close(ipc_sockets[1]), 0); 1611 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1612 EXPECT_EQ(close(ipc_sockets[0]), 0); 1613 1614 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1615 pid[i] = fork(); 1616 ASSERT_GE(pid[i], 0); 1617 if (pid[i] == 0) 1618 crashing_child(); 1619 pidfd[i] = sys_pidfd_open(pid[i], 0); 1620 ASSERT_GE(pidfd[i], 0); 1621 } 1622 1623 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1624 waitpid(pid[i], &status[i], 0); 1625 ASSERT_TRUE(WIFSIGNALED(status[i])); 1626 ASSERT_TRUE(WCOREDUMP(status[i])); 1627 } 1628 1629 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1630 info.mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP; 1631 ASSERT_EQ(ioctl(pidfd[i], PIDFD_GET_INFO, &info), 0); 1632 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1633 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1634 } 1635 1636 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1637 } 1638 1639 #define MAX_EVENTS 128 1640 1641 static void process_coredump_worker(int fd_coredump, int fd_peer_pidfd, int fd_core_file) 1642 { 1643 int epfd = -1; 1644 int exit_code = EXIT_FAILURE; 1645 1646 epfd = epoll_create1(0); 1647 if (epfd < 0) 1648 goto out; 1649 1650 struct epoll_event ev; 1651 ev.events = EPOLLIN | EPOLLRDHUP | EPOLLET; 1652 ev.data.fd = fd_coredump; 1653 if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd_coredump, &ev) < 0) 1654 goto out; 1655 1656 for (;;) { 1657 struct epoll_event events[1]; 1658 int n = epoll_wait(epfd, events, 1, -1); 1659 if (n < 0) 1660 break; 1661 1662 if (events[0].events & (EPOLLIN | EPOLLRDHUP)) { 1663 for (;;) { 1664 char buffer[4096]; 1665 ssize_t bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 1666 if (bytes_read < 0) { 1667 if (errno == EAGAIN || errno == EWOULDBLOCK) 1668 break; 1669 goto out; 1670 } 1671 if (bytes_read == 0) 1672 goto done; 1673 ssize_t bytes_write = write(fd_core_file, buffer, bytes_read); 1674 if (bytes_write != bytes_read) 1675 goto out; 1676 } 1677 } 1678 } 1679 1680 done: 1681 exit_code = EXIT_SUCCESS; 1682 out: 1683 if (epfd >= 0) 1684 close(epfd); 1685 if (fd_core_file >= 0) 1686 close(fd_core_file); 1687 if (fd_peer_pidfd >= 0) 1688 close(fd_peer_pidfd); 1689 if (fd_coredump >= 0) 1690 close(fd_coredump); 1691 _exit(exit_code); 1692 } 1693 1694 TEST_F_TIMEOUT(coredump, socket_multiple_crashing_coredumps_epoll_workers, 500) 1695 { 1696 int pidfd[NUM_CRASHING_COREDUMPS], status[NUM_CRASHING_COREDUMPS]; 1697 pid_t pid[NUM_CRASHING_COREDUMPS], pid_coredump_server, worker_pids[NUM_CRASHING_COREDUMPS]; 1698 struct pidfd_info info = {}; 1699 int ipc_sockets[2]; 1700 char c; 1701 1702 ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1703 ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets), 0); 1704 1705 pid_coredump_server = fork(); 1706 ASSERT_GE(pid_coredump_server, 0); 1707 if (pid_coredump_server == 0) { 1708 int fd_server = -1, exit_code = EXIT_FAILURE, n_conns = 0; 1709 fd_server = -1; 1710 exit_code = EXIT_FAILURE; 1711 n_conns = 0; 1712 close(ipc_sockets[0]); 1713 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1714 if (fd_server < 0) 1715 goto out; 1716 1717 if (write_nointr(ipc_sockets[1], "1", 1) < 0) 1718 goto out; 1719 close(ipc_sockets[1]); 1720 1721 while (n_conns < NUM_CRASHING_COREDUMPS) { 1722 int fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1; 1723 struct coredump_req req = {}; 1724 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1725 if (fd_coredump < 0) { 1726 if (errno == EAGAIN || errno == EWOULDBLOCK) 1727 continue; 1728 goto out; 1729 } 1730 fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1731 if (fd_peer_pidfd < 0) 1732 goto out; 1733 if (!get_pidfd_info(fd_peer_pidfd, &info)) 1734 goto out; 1735 if (!(info.mask & PIDFD_INFO_COREDUMP) || !(info.coredump_mask & PIDFD_COREDUMPED)) 1736 goto out; 1737 if (!read_coredump_req(fd_coredump, &req)) 1738 goto out; 1739 if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1740 COREDUMP_KERNEL | COREDUMP_USERSPACE | 1741 COREDUMP_REJECT | COREDUMP_WAIT)) 1742 goto out; 1743 if (!send_coredump_ack(fd_coredump, &req, COREDUMP_KERNEL | COREDUMP_WAIT, 0)) 1744 goto out; 1745 if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) 1746 goto out; 1747 fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached); 1748 if (fd_core_file < 0) 1749 goto out; 1750 pid_t worker = fork(); 1751 if (worker == 0) { 1752 close(fd_server); 1753 process_coredump_worker(fd_coredump, fd_peer_pidfd, fd_core_file); 1754 } 1755 worker_pids[n_conns] = worker; 1756 if (fd_coredump >= 0) 1757 close(fd_coredump); 1758 if (fd_peer_pidfd >= 0) 1759 close(fd_peer_pidfd); 1760 if (fd_core_file >= 0) 1761 close(fd_core_file); 1762 n_conns++; 1763 } 1764 exit_code = EXIT_SUCCESS; 1765 out: 1766 if (fd_server >= 0) 1767 close(fd_server); 1768 1769 // Reap all worker processes 1770 for (int i = 0; i < n_conns; i++) { 1771 int wstatus; 1772 if (waitpid(worker_pids[i], &wstatus, 0) < 0) { 1773 fprintf(stderr, "Failed to wait for worker %d: %m\n", worker_pids[i]); 1774 } else if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != EXIT_SUCCESS) { 1775 fprintf(stderr, "Worker %d exited with error code %d\n", worker_pids[i], WEXITSTATUS(wstatus)); 1776 exit_code = EXIT_FAILURE; 1777 } 1778 } 1779 1780 _exit(exit_code); 1781 } 1782 self->pid_coredump_server = pid_coredump_server; 1783 1784 EXPECT_EQ(close(ipc_sockets[1]), 0); 1785 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1786 EXPECT_EQ(close(ipc_sockets[0]), 0); 1787 1788 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1789 pid[i] = fork(); 1790 ASSERT_GE(pid[i], 0); 1791 if (pid[i] == 0) 1792 crashing_child(); 1793 pidfd[i] = sys_pidfd_open(pid[i], 0); 1794 ASSERT_GE(pidfd[i], 0); 1795 } 1796 1797 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1798 ASSERT_GE(waitpid(pid[i], &status[i], 0), 0); 1799 ASSERT_TRUE(WIFSIGNALED(status[i])); 1800 ASSERT_TRUE(WCOREDUMP(status[i])); 1801 } 1802 1803 for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1804 info.mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP; 1805 ASSERT_EQ(ioctl(pidfd[i], PIDFD_GET_INFO, &info), 0); 1806 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1807 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1808 } 1809 1810 wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1811 } 1812 1813 TEST_F(coredump, socket_invalid_paths) 1814 { 1815 ASSERT_FALSE(set_core_pattern("@ /tmp/coredump.socket")); 1816 ASSERT_FALSE(set_core_pattern("@/tmp/../coredump.socket")); 1817 ASSERT_FALSE(set_core_pattern("@../coredump.socket")); 1818 ASSERT_FALSE(set_core_pattern("@/tmp/coredump.socket/..")); 1819 ASSERT_FALSE(set_core_pattern("@..")); 1820 1821 ASSERT_FALSE(set_core_pattern("@@ /tmp/coredump.socket")); 1822 ASSERT_FALSE(set_core_pattern("@@/tmp/../coredump.socket")); 1823 ASSERT_FALSE(set_core_pattern("@@../coredump.socket")); 1824 ASSERT_FALSE(set_core_pattern("@@/tmp/coredump.socket/..")); 1825 ASSERT_FALSE(set_core_pattern("@@..")); 1826 1827 ASSERT_FALSE(set_core_pattern("@@@/tmp/coredump.socket")); 1828 } 1829 1830 TEST_HARNESS_MAIN 1831