Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/coredump: add coredump server selftests

This adds extensive tests for the coredump server.

Link: https://lore.kernel.org/20250603-work-coredump-socket-protocol-v2-5-05a5f0c18ecc@kernel.org
Acked-by: Lennart Poettering <lennart@poettering.net>
Reviewed-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>

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