Skip to content

Commit 3e32e3e

Browse files
committed
Merge branch 'vfs-6.19.coredump' into vfs.all
Signed-off-by: Christian Brauner <[email protected]>
2 parents 4ce3418 + 3f67947 commit 3e32e3e

File tree

11 files changed

+2914
-1700
lines changed

11 files changed

+2914
-1700
lines changed

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)