coredump: split pipe coredumping into coredump_pipe()

* Move that whole mess into a separate helper instead of having all that
  hanging around in vfs_coredump() directly. Cleanup paths are already
  centralized.

Link: https://lore.kernel.org/20250612-work-coredump-massage-v1-13-315c0c34ba94@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
Christian Brauner 2025-06-12 15:25:27 +02:00
parent 4f599219f7
commit 9f29a347d7
No known key found for this signature in database
GPG Key ID: 91C61BC06578DCA2

View File

@ -970,6 +970,63 @@ static bool coredump_file(struct core_name *cn, struct coredump_params *cprm,
return true;
}
static bool coredump_pipe(struct core_name *cn, struct coredump_params *cprm,
size_t *argv, int argc)
{
int argi;
char **helper_argv __free(kfree) = NULL;
struct subprocess_info *sub_info;
if (cprm->limit == 1) {
/* See umh_coredump_setup() which sets RLIMIT_CORE = 1.
*
* Normally core limits are irrelevant to pipes, since
* we're not writing to the file system, but we use
* cprm.limit of 1 here as a special value, this is a
* consistent way to catch recursive crashes.
* We can still crash if the core_pattern binary sets
* RLIM_CORE = !1, but it runs as root, and can do
* lots of stupid things.
*
* Note that we use task_tgid_vnr here to grab the pid
* of the process group leader. That way we get the
* right pid if a thread in a multi-threaded
* core_pattern process dies.
*/
coredump_report_failure("RLIMIT_CORE is set to 1, aborting core");
return false;
}
cprm->limit = RLIM_INFINITY;
cn->core_pipe_limit = atomic_inc_return(&core_pipe_count);
if (core_pipe_limit && (core_pipe_limit < cn->core_pipe_limit)) {
coredump_report_failure("over core_pipe_limit, skipping core dump");
return false;
}
helper_argv = kmalloc_array(argc + 1, sizeof(*helper_argv), GFP_KERNEL);
if (!helper_argv) {
coredump_report_failure("%s failed to allocate memory", __func__);
return false;
}
for (argi = 0; argi < argc; argi++)
helper_argv[argi] = cn->corename + argv[argi];
helper_argv[argi] = NULL;
sub_info = call_usermodehelper_setup(helper_argv[0], helper_argv, NULL,
GFP_KERNEL, umh_coredump_setup,
NULL, cprm);
if (!sub_info)
return false;
if (call_usermodehelper_exec(sub_info, UMH_WAIT_EXEC)) {
coredump_report_failure("|%s pipe failed", cn->corename);
return false;
}
return true;
}
void vfs_coredump(const kernel_siginfo_t *siginfo)
{
struct core_state core_state;
@ -1031,63 +1088,10 @@ void vfs_coredump(const kernel_siginfo_t *siginfo)
if (!coredump_file(&cn, &cprm, binfmt))
goto close_fail;
break;
case COREDUMP_PIPE: {
int argi;
char **helper_argv;
struct subprocess_info *sub_info;
if (cprm.limit == 1) {
/* See umh_coredump_setup() which sets RLIMIT_CORE = 1.
*
* Normally core limits are irrelevant to pipes, since
* we're not writing to the file system, but we use
* cprm.limit of 1 here as a special value, this is a
* consistent way to catch recursive crashes.
* We can still crash if the core_pattern binary sets
* RLIM_CORE = !1, but it runs as root, and can do
* lots of stupid things.
*
* Note that we use task_tgid_vnr here to grab the pid
* of the process group leader. That way we get the
* right pid if a thread in a multi-threaded
* core_pattern process dies.
*/
coredump_report_failure("RLIMIT_CORE is set to 1, aborting core");
case COREDUMP_PIPE:
if (!coredump_pipe(&cn, &cprm, argv, argc))
goto close_fail;
}
cprm.limit = RLIM_INFINITY;
cn.core_pipe_limit = atomic_inc_return(&core_pipe_count);
if (core_pipe_limit && (core_pipe_limit < cn.core_pipe_limit)) {
coredump_report_failure("over core_pipe_limit, skipping core dump");
goto close_fail;
}
helper_argv = kmalloc_array(argc + 1, sizeof(*helper_argv),
GFP_KERNEL);
if (!helper_argv) {
coredump_report_failure("%s failed to allocate memory", __func__);
goto close_fail;
}
for (argi = 0; argi < argc; argi++)
helper_argv[argi] = cn.corename + argv[argi];
helper_argv[argi] = NULL;
retval = -ENOMEM;
sub_info = call_usermodehelper_setup(helper_argv[0],
helper_argv, NULL, GFP_KERNEL,
umh_coredump_setup, NULL, &cprm);
if (sub_info)
retval = call_usermodehelper_exec(sub_info,
UMH_WAIT_EXEC);
kfree(helper_argv);
if (retval) {
coredump_report_failure("|%s pipe failed", cn.corename);
goto close_fail;
}
break;
}
case COREDUMP_SOCK_REQ:
fallthrough;
case COREDUMP_SOCK: