Skip to content

Commit a45ff1c

Browse files
committed
Merge patch series "coredump: cleanups & pidfd extension"
Christian Brauner <brauner@kernel.org> says: The recent changes to rework coredump handling to rely on unix sockets are in the process of being used in systemd. Yu reported on shortcoming nameling that the signal causing the coredump was available before the crashing process was reaped. 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 we need to have the signal number available before sending the coredump to the container. In general, the extension makes sense and fits with the rest of the coredump information. In addition to this extension this fixes a bunch of the tests that were failing and reworks the publication mechanism for exit and coredump info retrievable via the pidfd ioctl. * patches from https://patch.msgid.link/20251028-work-coredump-signal-v1-0-ca449b7b7aa0@kernel.org: (22 commits) 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 pidfs: add missing PIDFD_INFO_SIZE_VER1 ... Link: https://patch.msgid.link/20251028-work-coredump-signal-v1-0-ca449b7b7aa0@kernel.org Signed-off-by: Christian Brauner <brauner@kernel.org>
2 parents 3a86608 + cbb8425 commit a45ff1c

11 files changed

Lines changed: 2914 additions & 1700 deletions

File tree

fs/pidfs.c

Lines changed: 54 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -39,20 +39,20 @@ void pidfs_get_root(struct path *path)
3939
path_get(path);
4040
}
4141

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,
5045
};
5146

5247
struct pidfs_attr {
48+
unsigned long attr_mask;
5349
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;
5656
};
5757

5858
static struct rb_root pidfs_ino_tree = RB_ROOT;
@@ -293,19 +293,29 @@ static __u32 pidfs_coredump_mask(unsigned long mm_flags)
293293
return 0;
294294
}
295295

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+
296305
static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg)
297306
{
298307
struct pidfd_info __user *uinfo = (struct pidfd_info __user *)arg;
299308
struct task_struct *task __free(put_task) = NULL;
300309
struct pid *pid = pidfd_pid(file);
301310
size_t usize = _IOC_SIZE(cmd);
302311
struct pidfd_info kinfo = {};
303-
struct pidfs_exit_info *exit_info;
304312
struct user_namespace *user_ns;
305313
struct pidfs_attr *attr;
306314
const struct cred *c;
307315
__u64 mask;
308316

317+
BUILD_BUG_ON(sizeof(struct pidfd_info) != PIDFD_INFO_SIZE_VER2);
318+
309319
if (!uinfo)
310320
return -EINVAL;
311321
if (usize < PIDFD_INFO_SIZE_VER0)
@@ -323,20 +333,24 @@ static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg)
323333

324334
attr = READ_ONCE(pid->attr);
325335
if (mask & PIDFD_INFO_EXIT) {
326-
exit_info = READ_ONCE(attr->exit_info);
327-
if (exit_info) {
336+
if (test_bit(PIDFS_ATTR_BIT_EXIT, &attr->attr_mask)) {
337+
smp_rmb();
328338
kinfo.mask |= PIDFD_INFO_EXIT;
329339
#ifdef CONFIG_CGROUPS
330-
kinfo.cgroupid = exit_info->cgroupid;
340+
kinfo.cgroupid = attr->cgroupid;
331341
kinfo.mask |= PIDFD_INFO_CGROUPID;
332342
#endif
333-
kinfo.exit_code = exit_info->exit_code;
343+
kinfo.exit_code = attr->exit_code;
334344
}
335345
}
336346

337347
if (mask & PIDFD_INFO_COREDUMP) {
338-
kinfo.mask |= PIDFD_INFO_COREDUMP;
339-
kinfo.coredump_mask = READ_ONCE(attr->__pei.coredump_mask);
348+
if (test_bit(PIDFS_ATTR_BIT_COREDUMP, &attr->attr_mask)) {
349+
smp_rmb();
350+
kinfo.mask |= PIDFD_INFO_COREDUMP | PIDFD_INFO_COREDUMP_SIGNAL;
351+
kinfo.coredump_mask = attr->coredump_mask;
352+
kinfo.coredump_signal = attr->coredump_signal;
353+
}
340354
}
341355

342356
task = get_pid_task(pid, PIDTYPE_PID);
@@ -355,14 +369,15 @@ static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg)
355369
if (!c)
356370
return -ESRCH;
357371

358-
if ((kinfo.mask & PIDFD_INFO_COREDUMP) && !(kinfo.coredump_mask)) {
359-
task_lock(task);
372+
if ((mask & PIDFD_INFO_COREDUMP) && !kinfo.coredump_mask) {
373+
guard(task_lock)(task);
360374
if (task->mm) {
361375
unsigned long flags = __mm_flags_get_dumpable(task->mm);
362376

363377
kinfo.coredump_mask = pidfs_coredump_mask(flags);
378+
kinfo.mask |= PIDFD_INFO_COREDUMP;
379+
/* No coredump actually took place, so no coredump signal. */
364380
}
365-
task_unlock(task);
366381
}
367382

368383
/* Unconditionally return identifiers and credentials, the rest only on request */
@@ -409,6 +424,13 @@ static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg)
409424
return -ESRCH;
410425

411426
copy_out:
427+
if (mask & PIDFD_INFO_SUPPORTED_MASK) {
428+
kinfo.mask |= PIDFD_INFO_SUPPORTED_MASK;
429+
kinfo.supported_mask = PIDFD_INFO_SUPPORTED;
430+
}
431+
432+
/* Are there bits in the return mask not present in PIDFD_INFO_SUPPORTED? */
433+
WARN_ON_ONCE(~PIDFD_INFO_SUPPORTED & kinfo.mask);
412434
/*
413435
* If userspace and the kernel have the same struct size it can just
414436
* be copied. If userspace provides an older struct, only the bits that
@@ -606,7 +628,6 @@ void pidfs_exit(struct task_struct *tsk)
606628
{
607629
struct pid *pid = task_pid(tsk);
608630
struct pidfs_attr *attr;
609-
struct pidfs_exit_info *exit_info;
610631
#ifdef CONFIG_CGROUPS
611632
struct cgroup *cgrp;
612633
#endif
@@ -634,41 +655,39 @@ void pidfs_exit(struct task_struct *tsk)
634655
* is put
635656
*/
636657

637-
exit_info = &attr->__pei;
638-
639658
#ifdef CONFIG_CGROUPS
640659
rcu_read_lock();
641660
cgrp = task_dfl_cgroup(tsk);
642-
exit_info->cgroupid = cgroup_id(cgrp);
661+
attr->cgroupid = cgroup_id(cgrp);
643662
rcu_read_unlock();
644663
#endif
645-
exit_info->exit_code = tsk->exit_code;
664+
attr->exit_code = tsk->exit_code;
646665

647666
/* Ensure that PIDFD_GET_INFO sees either all or nothing. */
648-
smp_store_release(&attr->exit_info, &attr->__pei);
667+
smp_wmb();
668+
set_bit(PIDFS_ATTR_BIT_EXIT, &attr->attr_mask);
649669
}
650670

651671
#ifdef CONFIG_COREDUMP
652672
void pidfs_coredump(const struct coredump_params *cprm)
653673
{
654674
struct pid *pid = cprm->pid;
655-
struct pidfs_exit_info *exit_info;
656675
struct pidfs_attr *attr;
657-
__u32 coredump_mask = 0;
658676

659677
attr = READ_ONCE(pid->attr);
660678

661679
VFS_WARN_ON_ONCE(!attr);
662680
VFS_WARN_ON_ONCE(attr == PIDFS_PID_DEAD);
663681

664-
exit_info = &attr->__pei;
665-
/* Note how we were coredumped. */
666-
coredump_mask = pidfs_coredump_mask(cprm->mm_flags);
667-
/* Note that we actually did coredump. */
668-
coredump_mask |= PIDFD_COREDUMPED;
682+
/* Note how we were coredumped and that we coredumped. */
683+
attr->coredump_mask = pidfs_coredump_mask(cprm->mm_flags) |
684+
PIDFD_COREDUMPED;
669685
/* If coredumping is set to skip we should never end up here. */
670-
VFS_WARN_ON_ONCE(coredump_mask & PIDFD_COREDUMP_SKIP);
671-
smp_store_release(&exit_info->coredump_mask, coredump_mask);
686+
VFS_WARN_ON_ONCE(attr->coredump_mask & PIDFD_COREDUMP_SKIP);
687+
/* Expose the signal number that caused the coredump. */
688+
attr->coredump_signal = cprm->siginfo->si_signo;
689+
smp_wmb();
690+
set_bit(PIDFS_ATTR_BIT_COREDUMP, &attr->attr_mask);
672691
}
673692
#endif
674693

include/uapi/linux/pidfd.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,12 @@
2626
#define PIDFD_INFO_CGROUPID (1UL << 2) /* Always returned if available, even if not requested */
2727
#define PIDFD_INFO_EXIT (1UL << 3) /* Only returned if requested. */
2828
#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. */
2931

3032
#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 */
3135

3236
/*
3337
* Values for @coredump_mask in pidfd_info.
@@ -91,8 +95,11 @@ struct pidfd_info {
9195
__u32 fsuid;
9296
__u32 fsgid;
9397
__s32 exit_code;
94-
__u32 coredump_mask;
95-
__u32 __spare1;
98+
struct /* coredump info */ {
99+
__u32 coredump_mask;
100+
__u32 coredump_signal;
101+
};
102+
__u64 supported_mask; /* Mask flags that this kernel supports */
96103
};
97104

98105
#define PIDFS_IOCTL_MAGIC 0xFF
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# SPDX-License-Identifier: GPL-2.0-only
2+
stackdump_test
3+
coredump_socket_test
4+
coredump_socket_protocol_test
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22
CFLAGS += -Wall -O0 -g $(KHDR_INCLUDES) $(TOOLS_INCLUDES)
33

4-
TEST_GEN_PROGS := stackdump_test
4+
TEST_GEN_PROGS := stackdump_test \
5+
coredump_socket_test \
6+
coredump_socket_protocol_test
57
TEST_FILES := stackdump
68

79
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

0 commit comments

Comments
 (0)