Skip to content

Commit b5325b2

Browse files
committed
coredump: hand a pidfd to the usermode coredump helper
Give userspace a way to instruct the kernel to install a pidfd into the usermode helper process. This makes coredump handling a lot more reliable for userspace. In parallel with this commit we already have systemd adding support for this in [1]. We create a pidfs file for the coredumping process when we process the corename pattern. When the usermode helper process is forked we then install the pidfs file as file descriptor three into the usermode helpers file descriptor table so it's available to the exec'd program. Since usermode helpers are either children of the system_unbound_wq workqueue or kthreadd we know that the file descriptor table is empty and can thus always use three as the file descriptor number. Note, that we'll install a pidfd for the thread-group leader even if a subthread is calling do_coredump(). We know that task linkage hasn't been removed due to delay_group_leader() and even if this @current isn't the actual thread-group leader we know that the thread-group leader cannot be reaped until @current has exited. Link: systemd/systemd#37125 [1] Link: https://lore.kernel.org/[email protected] Tested-by: Luca Boccassi <[email protected]> Reviewed-by: Oleg Nesterov <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent 95c5f43 commit b5325b2

File tree

2 files changed

+53
-4
lines changed

2 files changed

+53
-4
lines changed

fs/coredump.c

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
#include <linux/timekeeping.h>
4444
#include <linux/sysctl.h>
4545
#include <linux/elf.h>
46+
#include <linux/pidfs.h>
47+
#include <uapi/linux/pidfd.h>
4648

4749
#include <linux/uaccess.h>
4850
#include <asm/mmu_context.h>
@@ -60,6 +62,12 @@ static void free_vma_snapshot(struct coredump_params *cprm);
6062
#define CORE_FILE_NOTE_SIZE_DEFAULT (4*1024*1024)
6163
/* Define a reasonable max cap */
6264
#define CORE_FILE_NOTE_SIZE_MAX (16*1024*1024)
65+
/*
66+
* File descriptor number for the pidfd for the thread-group leader of
67+
* the coredumping task installed into the usermode helper's file
68+
* descriptor table.
69+
*/
70+
#define COREDUMP_PIDFD_NUMBER 3
6371

6472
static int core_uses_pid;
6573
static unsigned int core_pipe_limit;
@@ -339,6 +347,27 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm,
339347
case 'C':
340348
err = cn_printf(cn, "%d", cprm->cpu);
341349
break;
350+
/* pidfd number */
351+
case 'F': {
352+
/*
353+
* Installing a pidfd only makes sense if
354+
* we actually spawn a usermode helper.
355+
*/
356+
if (!ispipe)
357+
break;
358+
359+
/*
360+
* Note that we'll install a pidfd for the
361+
* thread-group leader. We know that task
362+
* linkage hasn't been removed yet and even if
363+
* this @current isn't the actual thread-group
364+
* leader we know that the thread-group leader
365+
* cannot be reaped until @current has exited.
366+
*/
367+
cprm->pid = task_tgid(current);
368+
err = cn_printf(cn, "%d", COREDUMP_PIDFD_NUMBER);
369+
break;
370+
}
342371
default:
343372
break;
344373
}
@@ -493,7 +522,7 @@ static void wait_for_dump_helpers(struct file *file)
493522
}
494523

495524
/*
496-
* umh_pipe_setup
525+
* umh_coredump_setup
497526
* helper function to customize the process used
498527
* to collect the core in userspace. Specifically
499528
* it sets up a pipe and installs it as fd 0 (stdin)
@@ -503,12 +532,31 @@ static void wait_for_dump_helpers(struct file *file)
503532
* is a special value that we use to trap recursive
504533
* core dumps
505534
*/
506-
static int umh_pipe_setup(struct subprocess_info *info, struct cred *new)
535+
static int umh_coredump_setup(struct subprocess_info *info, struct cred *new)
507536
{
508537
struct file *files[2];
509538
struct coredump_params *cp = (struct coredump_params *)info->data;
510539
int err;
511540

541+
if (cp->pid) {
542+
struct file *pidfs_file __free(fput) = NULL;
543+
544+
pidfs_file = pidfs_alloc_file(cp->pid, 0);
545+
if (IS_ERR(pidfs_file))
546+
return PTR_ERR(pidfs_file);
547+
548+
/*
549+
* Usermode helpers are childen of either
550+
* system_unbound_wq or of kthreadd. So we know that
551+
* we're starting off with a clean file descriptor
552+
* table. So we should always be able to use
553+
* COREDUMP_PIDFD_NUMBER as our file descriptor value.
554+
*/
555+
err = replace_fd(COREDUMP_PIDFD_NUMBER, pidfs_file, 0);
556+
if (err < 0)
557+
return err;
558+
}
559+
512560
err = create_pipe_files(files, 0);
513561
if (err)
514562
return err;
@@ -598,7 +646,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
598646
}
599647

600648
if (cprm.limit == 1) {
601-
/* See umh_pipe_setup() which sets RLIMIT_CORE = 1.
649+
/* See umh_coredump_setup() which sets RLIMIT_CORE = 1.
602650
*
603651
* Normally core limits are irrelevant to pipes, since
604652
* we're not writing to the file system, but we use
@@ -637,7 +685,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
637685
retval = -ENOMEM;
638686
sub_info = call_usermodehelper_setup(helper_argv[0],
639687
helper_argv, NULL, GFP_KERNEL,
640-
umh_pipe_setup, NULL, &cprm);
688+
umh_coredump_setup, NULL, &cprm);
641689
if (sub_info)
642690
retval = call_usermodehelper_exec(sub_info,
643691
UMH_WAIT_EXEC);

include/linux/coredump.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ struct coredump_params {
2828
int vma_count;
2929
size_t vma_data_size;
3030
struct core_vma_metadata *vma_meta;
31+
struct pid *pid;
3132
};
3233

3334
extern unsigned int core_file_note_size_limit;

0 commit comments

Comments
 (0)