Skip to content

Commit 1d8db6f

Browse files
committed
pidfs, coredump: add PIDFD_INFO_COREDUMP
Extend the PIDFD_INFO_COREDUMP ioctl() with the new PIDFD_INFO_COREDUMP mask flag. This adds the @coredump_mask field to struct pidfd_info. When a task coredumps the kernel will provide the following information to userspace in @coredump_mask: * PIDFD_COREDUMPED is raised if the task did actually coredump. * PIDFD_COREDUMP_SKIP is raised if the task skipped coredumping (e.g., undumpable). * PIDFD_COREDUMP_USER is raised if this is a regular coredump and doesn't need special care by the coredump server. * PIDFD_COREDUMP_ROOT is raised if the generated coredump should be treated as sensitive and the coredump server should restrict to the generated coredump to sufficiently privileged users. The kernel guarantees that by the time the connection is made the all PIDFD_INFO_COREDUMP info is available. Link: https://lore.kernel.org/[email protected] Acked-by: Luca Boccassi <[email protected]> Reviewed-by: Alexander Mikhalitsyn <[email protected]> Reviewed-by: Jann Horn <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent a9194f8 commit 1d8db6f

File tree

4 files changed

+107
-0
lines changed

4 files changed

+107
-0
lines changed

fs/coredump.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@
4646
#include <linux/pidfs.h>
4747
#include <linux/net.h>
4848
#include <linux/socket.h>
49+
#include <net/af_unix.h>
4950
#include <net/net_namespace.h>
51+
#include <net/sock.h>
5052
#include <uapi/linux/pidfd.h>
5153
#include <uapi/linux/un.h>
5254

@@ -599,6 +601,8 @@ static int umh_coredump_setup(struct subprocess_info *info, struct cred *new)
599601
if (IS_ERR(pidfs_file))
600602
return PTR_ERR(pidfs_file);
601603

604+
pidfs_coredump(cp);
605+
602606
/*
603607
* Usermode helpers are childen of either
604608
* system_unbound_wq or of kthreadd. So we know that
@@ -875,8 +879,31 @@ void do_coredump(const kernel_siginfo_t *siginfo)
875879
if (IS_ERR(file))
876880
goto close_fail;
877881

882+
/*
883+
* Set the thread-group leader pid which is used for the
884+
* peer credentials during connect() below. Then
885+
* immediately register it in pidfs...
886+
*/
887+
cprm.pid = task_tgid(current);
888+
retval = pidfs_register_pid(cprm.pid);
889+
if (retval)
890+
goto close_fail;
891+
892+
/*
893+
* ... and set the coredump information so userspace
894+
* has it available after connect()...
895+
*/
896+
pidfs_coredump(&cprm);
897+
878898
retval = kernel_connect(socket, (struct sockaddr *)(&addr),
879899
addr_len, O_NONBLOCK | SOCK_COREDUMP);
900+
901+
/*
902+
* ... Make sure to only put our reference after connect() took
903+
* its own reference keeping the pidfs entry alive ...
904+
*/
905+
pidfs_put_pid(cprm.pid);
906+
880907
if (retval) {
881908
if (retval == -EAGAIN)
882909
coredump_report_failure("Coredump socket %s receive queue full", addr.sun_path);
@@ -885,6 +912,10 @@ void do_coredump(const kernel_siginfo_t *siginfo)
885912
goto close_fail;
886913
}
887914

915+
/* ... and validate that @sk_peer_pid matches @cprm.pid. */
916+
if (WARN_ON_ONCE(unix_peer(socket->sk)->sk_peer_pid != cprm.pid))
917+
goto close_fail;
918+
888919
cprm.limit = RLIM_INFINITY;
889920
cprm.file = no_free_ptr(file);
890921
#else

fs/pidfs.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/time_namespace.h>
2121
#include <linux/utsname.h>
2222
#include <net/net_namespace.h>
23+
#include <linux/coredump.h>
2324

2425
#include "internal.h"
2526
#include "mount.h"
@@ -33,6 +34,7 @@ static struct kmem_cache *pidfs_cachep __ro_after_init;
3334
struct pidfs_exit_info {
3435
__u64 cgroupid;
3536
__s32 exit_code;
37+
__u32 coredump_mask;
3638
};
3739

3840
struct pidfs_inode {
@@ -240,6 +242,22 @@ static inline bool pid_in_current_pidns(const struct pid *pid)
240242
return false;
241243
}
242244

245+
static __u32 pidfs_coredump_mask(unsigned long mm_flags)
246+
{
247+
switch (__get_dumpable(mm_flags)) {
248+
case SUID_DUMP_USER:
249+
return PIDFD_COREDUMP_USER;
250+
case SUID_DUMP_ROOT:
251+
return PIDFD_COREDUMP_ROOT;
252+
case SUID_DUMP_DISABLE:
253+
return PIDFD_COREDUMP_SKIP;
254+
default:
255+
WARN_ON_ONCE(true);
256+
}
257+
258+
return 0;
259+
}
260+
243261
static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg)
244262
{
245263
struct pidfd_info __user *uinfo = (struct pidfd_info __user *)arg;
@@ -280,6 +298,11 @@ static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg)
280298
}
281299
}
282300

301+
if (mask & PIDFD_INFO_COREDUMP) {
302+
kinfo.mask |= PIDFD_INFO_COREDUMP;
303+
kinfo.coredump_mask = READ_ONCE(pidfs_i(inode)->__pei.coredump_mask);
304+
}
305+
283306
task = get_pid_task(pid, PIDTYPE_PID);
284307
if (!task) {
285308
/*
@@ -296,6 +319,13 @@ static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg)
296319
if (!c)
297320
return -ESRCH;
298321

322+
if (!(kinfo.mask & PIDFD_INFO_COREDUMP)) {
323+
task_lock(task);
324+
if (task->mm)
325+
kinfo.coredump_mask = pidfs_coredump_mask(task->mm->flags);
326+
task_unlock(task);
327+
}
328+
299329
/* Unconditionally return identifiers and credentials, the rest only on request */
300330

301331
user_ns = current_user_ns();
@@ -559,6 +589,31 @@ void pidfs_exit(struct task_struct *tsk)
559589
}
560590
}
561591

592+
#ifdef CONFIG_COREDUMP
593+
void pidfs_coredump(const struct coredump_params *cprm)
594+
{
595+
struct pid *pid = cprm->pid;
596+
struct pidfs_exit_info *exit_info;
597+
struct dentry *dentry;
598+
struct inode *inode;
599+
__u32 coredump_mask = 0;
600+
601+
dentry = pid->stashed;
602+
if (WARN_ON_ONCE(!dentry))
603+
return;
604+
605+
inode = d_inode(dentry);
606+
exit_info = &pidfs_i(inode)->__pei;
607+
/* Note how we were coredumped. */
608+
coredump_mask = pidfs_coredump_mask(cprm->mm_flags);
609+
/* Note that we actually did coredump. */
610+
coredump_mask |= PIDFD_COREDUMPED;
611+
/* If coredumping is set to skip we should never end up here. */
612+
VFS_WARN_ON_ONCE(coredump_mask & PIDFD_COREDUMP_SKIP);
613+
smp_store_release(&exit_info->coredump_mask, coredump_mask);
614+
}
615+
#endif
616+
562617
static struct vfsmount *pidfs_mnt __ro_after_init;
563618

564619
/*

include/linux/pidfs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@
22
#ifndef _LINUX_PID_FS_H
33
#define _LINUX_PID_FS_H
44

5+
struct coredump_params;
6+
57
struct file *pidfs_alloc_file(struct pid *pid, unsigned int flags);
68
void __init pidfs_init(void);
79
void pidfs_add_pid(struct pid *pid);
810
void pidfs_remove_pid(struct pid *pid);
911
void pidfs_exit(struct task_struct *tsk);
12+
#ifdef CONFIG_COREDUMP
13+
void pidfs_coredump(const struct coredump_params *cprm);
14+
#endif
1015
extern const struct dentry_operations pidfs_dentry_operations;
1116
int pidfs_register_pid(struct pid *pid);
1217
void pidfs_get_pid(struct pid *pid);

include/uapi/linux/pidfd.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,23 @@
2525
#define PIDFD_INFO_CREDS (1UL << 1) /* Always returned, even if not requested */
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. */
28+
#define PIDFD_INFO_COREDUMP (1UL << 4) /* Only returned if requested. */
2829

2930
#define PIDFD_INFO_SIZE_VER0 64 /* sizeof first published struct */
3031

32+
/*
33+
* Values for @coredump_mask in pidfd_info.
34+
* Only valid if PIDFD_INFO_COREDUMP is set in @mask.
35+
*
36+
* Note, the @PIDFD_COREDUMP_ROOT flag indicates that the generated
37+
* coredump should be treated as sensitive and access should only be
38+
* granted to privileged users.
39+
*/
40+
#define PIDFD_COREDUMPED (1U << 0) /* Did crash and... */
41+
#define PIDFD_COREDUMP_SKIP (1U << 1) /* coredumping generation was skipped. */
42+
#define PIDFD_COREDUMP_USER (1U << 2) /* coredump was done as the user. */
43+
#define PIDFD_COREDUMP_ROOT (1U << 3) /* coredump was done as root. */
44+
3145
/*
3246
* The concept of process and threads in userland and the kernel is a confusing
3347
* one - within the kernel every thread is a 'task' with its own individual PID,
@@ -92,6 +106,8 @@ struct pidfd_info {
92106
__u32 fsuid;
93107
__u32 fsgid;
94108
__s32 exit_code;
109+
__u32 coredump_mask;
110+
__u32 __spare1;
95111
};
96112

97113
#define PIDFS_IOCTL_MAGIC 0xFF

0 commit comments

Comments
 (0)