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

Merge tag 'vfs-6.19-rc1.coredump' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull pidfd and coredump updates from Christian Brauner:
"Features:

- Expose coredump signal via pidfd

Expose the signal that caused the coredump through the pidfd
interface. The recent changes to rework coredump handling to rely
on unix sockets are in the process of being used in systemd. The
previous systemd coredump container interface requires the coredump
file descriptor and basic information including the signal number
to be sent to the container. This means the signal number needs to
be available before sending the coredump to the container.

- Add supported_mask field to pidfd

Add a new supported_mask field to struct pidfd_info that indicates
which information fields are supported by the running kernel. This
allows userspace to detect feature availability without relying on
error codes or kernel version checks.

Cleanups:

- Drop struct pidfs_exit_info and prepare to drop exit_info pointer,
simplifying the internal publication mechanism for exit and
coredump information retrievable via the pidfd ioctl

- Use guard() for task_lock in pidfs

- Reduce wait_pidfd lock scope

- Add missing PIDFD_INFO_SIZE_VER1 constant

- Add missing BUILD_BUG_ON() assert on struct pidfd_info

Fixes:

- Fix PIDFD_INFO_COREDUMP handling

Selftests:

- Split out coredump socket tests and common helpers into separate
files for better organization

- Fix userspace coredump client detection issues

- Handle edge-triggered epoll correctly

- Ignore ENOSPC errors in tests

- Add debug logging to coredump socket tests, socket protocol tests,
and test helpers

- Add tests for PIDFD_INFO_COREDUMP_SIGNAL

- Add tests for supported_mask field

- Update pidfd header for selftests"

* tag 'vfs-6.19-rc1.coredump' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (23 commits)
pidfs: reduce wait_pidfd lock scope
selftests/coredump: add second PIDFD_INFO_COREDUMP_SIGNAL test
selftests/coredump: add first PIDFD_INFO_COREDUMP_SIGNAL test
selftests/coredump: ignore ENOSPC errors
selftests/coredump: add debug logging to coredump socket protocol tests
selftests/coredump: add debug logging to coredump socket tests
selftests/coredump: add debug logging to test helpers
selftests/coredump: handle edge-triggered epoll correctly
selftests/coredump: fix userspace coredump client detection
selftests/coredump: fix userspace client detection
selftests/coredump: split out coredump socket tests
selftests/coredump: split out common helpers
selftests/pidfd: add second supported_mask test
selftests/pidfd: add first supported_mask test
selftests/pidfd: update pidfd header
pidfs: expose coredump signal
pidfs: drop struct pidfs_exit_info
pidfs: prepare to drop exit_info pointer
pidfd: add a new supported_mask field
pidfs: add missing BUILD_BUG_ON() assert on struct pidfd_info
...

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