Unverified Commit d4fde206 authored by Christian Brauner's avatar Christian Brauner
Browse files

coredump: massage do_coredump()

We're going to extend the coredump code in follow-up patches.
Clean it up so we can do this more easily.

Link: https://lore.kernel.org/20250516-work-coredump-socket-v8-2-664f3caf2516@kernel.org


Acked-by: default avatarLuca Boccassi <luca.boccassi@gmail.com>
Reviewed-by: default avatarJann Horn <jannh@google.com>
Reviewed-by: default avatarAlexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parent 727b5510
Loading
Loading
Loading
Loading
+65 −57
Original line number Diff line number Diff line
@@ -643,63 +643,8 @@ void do_coredump(const kernel_siginfo_t *siginfo)
		goto fail_unlock;
	}

	if (cn.core_type == COREDUMP_PIPE) {
		int argi;
		int dump_count;
		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");
			goto fail_unlock;
		}
		cprm.limit = RLIM_INFINITY;

		dump_count = atomic_inc_return(&core_dump_count);
		if (core_pipe_limit && (core_pipe_limit < dump_count)) {
			coredump_report_failure("over core_pipe_limit, skipping core dump");
			goto fail_dropcount;
		}

		helper_argv = kmalloc_array(argc + 1, sizeof(*helper_argv),
					    GFP_KERNEL);
		if (!helper_argv) {
			coredump_report_failure("%s failed to allocate memory", __func__);
			goto fail_dropcount;
		}
		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;
		}
	} else if (cn.core_type == COREDUMP_FILE) {
	switch (cn.core_type) {
	case COREDUMP_FILE: {
		struct mnt_idmap *idmap;
		struct inode *inode;
		int open_flags = O_CREAT | O_WRONLY | O_NOFOLLOW |
@@ -793,6 +738,69 @@ void do_coredump(const kernel_siginfo_t *siginfo)
		if (do_truncate(idmap, cprm.file->f_path.dentry,
				0, 0, cprm.file))
			goto close_fail;
		break;
	}
	case COREDUMP_PIPE: {
		int argi;
		int dump_count;
		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");
			goto fail_unlock;
		}
		cprm.limit = RLIM_INFINITY;

		dump_count = atomic_inc_return(&core_dump_count);
		if (core_pipe_limit && (core_pipe_limit < dump_count)) {
			coredump_report_failure("over core_pipe_limit, skipping core dump");
			goto fail_dropcount;
		}

		helper_argv = kmalloc_array(argc + 1, sizeof(*helper_argv),
					    GFP_KERNEL);
		if (!helper_argv) {
			coredump_report_failure("%s failed to allocate memory", __func__);
			goto fail_dropcount;
		}
		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;
	}
	default:
		WARN_ON_ONCE(true);
		goto close_fail;
	}

	/* get us an unshared descriptor table; almost always a no-op */