Skip to content

Commit ac19091

Browse files
braunergregkh
authored andcommitted
coredump: hand a pidfd to the usermode coredump helper
commit b5325b2a270fcaf7b2a9a0f23d422ca8a5a8bdea upstream. 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. [brauner: This is a backport for the v6.1 series. Upstream has significantly changed and backporting all that infra is a non-starter. So simply backport the pidfd_prepare() helper and waste the file descriptor we allocated. Then we minimally massage the umh coredump setup code.] 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]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent b2a5bf1 commit ac19091

File tree

2 files changed

+72
-7
lines changed

2 files changed

+72
-7
lines changed

fs/coredump.c

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include <linux/timekeeping.h>
4343
#include <linux/sysctl.h>
4444
#include <linux/elf.h>
45+
#include <uapi/linux/pidfd.h>
4546

4647
#include <linux/uaccess.h>
4748
#include <asm/mmu_context.h>
@@ -56,6 +57,13 @@
5657
static bool dump_vma_snapshot(struct coredump_params *cprm);
5758
static void free_vma_snapshot(struct coredump_params *cprm);
5859

60+
/*
61+
* File descriptor number for the pidfd for the thread-group leader of
62+
* the coredumping task installed into the usermode helper's file
63+
* descriptor table.
64+
*/
65+
#define COREDUMP_PIDFD_NUMBER 3
66+
5967
static int core_uses_pid;
6068
static unsigned int core_pipe_limit;
6169
static char core_pattern[CORENAME_MAX_SIZE] = "core";
@@ -325,6 +333,27 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm,
325333
err = cn_printf(cn, "%lu",
326334
rlimit(RLIMIT_CORE));
327335
break;
336+
/* pidfd number */
337+
case 'F': {
338+
/*
339+
* Installing a pidfd only makes sense if
340+
* we actually spawn a usermode helper.
341+
*/
342+
if (!ispipe)
343+
break;
344+
345+
/*
346+
* Note that we'll install a pidfd for the
347+
* thread-group leader. We know that task
348+
* linkage hasn't been removed yet and even if
349+
* this @current isn't the actual thread-group
350+
* leader we know that the thread-group leader
351+
* cannot be reaped until @current has exited.
352+
*/
353+
cprm->pid = task_tgid(current);
354+
err = cn_printf(cn, "%d", COREDUMP_PIDFD_NUMBER);
355+
break;
356+
}
328357
default:
329358
break;
330359
}
@@ -479,7 +508,7 @@ static void wait_for_dump_helpers(struct file *file)
479508
}
480509

481510
/*
482-
* umh_pipe_setup
511+
* umh_coredump_setup
483512
* helper function to customize the process used
484513
* to collect the core in userspace. Specifically
485514
* it sets up a pipe and installs it as fd 0 (stdin)
@@ -489,27 +518,62 @@ static void wait_for_dump_helpers(struct file *file)
489518
* is a special value that we use to trap recursive
490519
* core dumps
491520
*/
492-
static int umh_pipe_setup(struct subprocess_info *info, struct cred *new)
521+
static int umh_coredump_setup(struct subprocess_info *info, struct cred *new)
493522
{
494523
struct file *files[2];
524+
struct file *pidfs_file = NULL;
495525
struct coredump_params *cp = (struct coredump_params *)info->data;
496526
int err;
497527

528+
if (cp->pid) {
529+
int fd;
530+
531+
fd = pidfd_prepare(cp->pid, 0, &pidfs_file);
532+
if (fd < 0)
533+
return fd;
534+
535+
/*
536+
* We don't care about the fd. We also cannot simply
537+
* replace it below because dup2() will refuse to close
538+
* this file descriptor if its in a larval state. So
539+
* close it!
540+
*/
541+
put_unused_fd(fd);
542+
543+
/*
544+
* Usermode helpers are childen of either
545+
* system_unbound_wq or of kthreadd. So we know that
546+
* we're starting off with a clean file descriptor
547+
* table. So we should always be able to use
548+
* COREDUMP_PIDFD_NUMBER as our file descriptor value.
549+
*/
550+
err = replace_fd(COREDUMP_PIDFD_NUMBER, pidfs_file, 0);
551+
if (err < 0)
552+
goto out_fail;
553+
554+
pidfs_file = NULL;
555+
}
556+
498557
err = create_pipe_files(files, 0);
499558
if (err)
500-
return err;
559+
goto out_fail;
501560

502561
cp->file = files[1];
503562

504563
err = replace_fd(0, files[0], 0);
505564
fput(files[0]);
506565
if (err < 0)
507-
return err;
566+
goto out_fail;
508567

509568
/* and disallow core files too */
510569
current->signal->rlim[RLIMIT_CORE] = (struct rlimit){1, 1};
511570

512-
return 0;
571+
err = 0;
572+
573+
out_fail:
574+
if (pidfs_file)
575+
fput(pidfs_file);
576+
return err;
513577
}
514578

515579
void do_coredump(const kernel_siginfo_t *siginfo)
@@ -585,7 +649,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
585649
}
586650

587651
if (cprm.limit == 1) {
588-
/* See umh_pipe_setup() which sets RLIMIT_CORE = 1.
652+
/* See umh_coredump_setup() which sets RLIMIT_CORE = 1.
589653
*
590654
* Normally core limits are irrelevant to pipes, since
591655
* we're not writing to the file system, but we use
@@ -630,7 +694,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
630694
retval = -ENOMEM;
631695
sub_info = call_usermodehelper_setup(helper_argv[0],
632696
helper_argv, NULL, GFP_KERNEL,
633-
umh_pipe_setup, NULL, &cprm);
697+
umh_coredump_setup, NULL, &cprm);
634698
if (sub_info)
635699
retval = call_usermodehelper_exec(sub_info,
636700
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
/*

0 commit comments

Comments
 (0)