From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out02.mta.xmission.com (out02.mta.xmission.com [166.70.13.232]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 552CF39F190 for ; Fri, 26 Jun 2026 16:55:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=166.70.13.232 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782492948; cv=none; b=DvrozfuWI2Tf984f7H6yZaOm5LZoavnYWOgJwOhc/0iflpHT40q0WenJ1jlZ37L7eVJ95GSdqOuYUPi5zdXzgreuX6hliHA321PUs0SOeN+fD1S7q/Ruh847gXDDUzsk6f7ucpOUVX0IcuPalb2xOaOUCNGWTki3Q97BpPOQUTM= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782492948; c=relaxed/simple; bh=EVZVSsop60kCCd/eGrg6kKo2uazPvp2s5MDBKOj8FH8=; h=From:To:Cc:In-Reply-To:References:Date:Message-ID:MIME-Version: Content-Type:Subject; b=T7SHieze4XWDXH5GjBcCJy0ESQrDmNZpyx1rlz3Wy2Mifhb/JhIIMNYbGyakpXVeCKnczKZG6H1Z519iG0LJyMpgJY/hZ7bE/7btOZ2PHCz9xVDRkTPU6kcI7QYelDT6sAH8rAKx2zprY/nElEpUj7DDI0b2O/9nh6qVMVL39Y8= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=xmission.com; spf=pass smtp.mailfrom=xmission.com; dkim=pass (1024-bit key) header.d=xmission.com header.i=@xmission.com header.b=NBtH7Fwa; arc=none smtp.client-ip=166.70.13.232 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=xmission.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=xmission.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=xmission.com header.i=@xmission.com header.b="NBtH7Fwa" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=simple/simple; d=xmission.com; s=xmission; h=Subject:Content-Type:MIME-Version:Message-ID:Date:References: In-Reply-To:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=EVZVSsop60kCCd/eGrg6kKo2uazPvp2s5MDBKOj8FH8=; b=NBtH7Fwa5N05drx/UXZVTIehnm DJHBnqvgQ3Srr8wCLDZSzXmMsyHmf0ghglgrdRZpekwZo+/ljnx4fxRS1T3qIdpVXJ6cDdD/EYVAu hE70QZaoWydsqlRx4kJGf69kB4UV6oVoHs6q2DGkvLQNab7wC4IxnUlOGgy7OvSU1pt8=; Received: from in01.mta.xmission.com ([166.70.13.51]:42426) by out02.mta.xmission.com with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.93) (envelope-from ) id 1wd9qD-008ijd-48; Fri, 26 Jun 2026 10:55:45 -0600 Received: from ip72-198-198-28.om.om.cox.net ([72.198.198.28]:46968 helo=email.froward.int.ebiederm.org.xmission.com) by in01.mta.xmission.com with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.93) (envelope-from ) id 1wd9qB-00Gjyx-Qp; Fri, 26 Jun 2026 10:55:44 -0600 From: "Eric W. Biederman" To: Andrew Morton Cc: Andy Lutomirski , Kees Cook , Kusaram Devineni , Peter Zijlstra , Thomas Gleixner , Will Drewry , linux-kernel@vger.kernel.org, Oleg Nesterov In-Reply-To: <87o6gx9rc4.fsf@email.froward.int.ebiederm.org> (Eric W. Biederman's message of "Fri, 26 Jun 2026 11:52:43 -0500") References: <87o6gx9rc4.fsf@email.froward.int.ebiederm.org> Date: Fri, 26 Jun 2026 11:55:38 -0500 Message-ID: <871pdt9r79.fsf_-_@email.froward.int.ebiederm.org> User-Agent: Gnus/5.13 (Gnus v5.13) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain X-XM-SPF: eid=1wd9qB-00Gjyx-Qp;;;mid=<871pdt9r79.fsf_-_@email.froward.int.ebiederm.org>;;;hst=in01.mta.xmission.com;;;ip=72.198.198.28;;;frm=ebiederm@xmission.com;;;sPfnum=0;;;sPf=pass X-XM-AID: U2FsdGVkX19K/JCxQaW/hZjBYdhOyEnNT7xADmQJLsA= X-Spam-Level: * X-Spam-Virus: No X-Spam-Report: * -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP * 0.1 BAYES_50 BODY: Bayes spam probability is 40 to 60% * [score: 0.5000] * 0.7 XMSubLong Long Subject * 1.5 XMNoVowels Alpha-numberic number with no vowels * -0.0 DCC_CHECK_NEGATIVE Not listed in DCC * [sa02 1397; Body=1 Fuz1=1 Fuz2=1] * 0.0 T_TooManySym_01 4+ unique symbols in subject * 0.0 XM_B_AI_SPAM_COMBINATION Email matches multiple AI-related * patterns X-Spam-DCC: XMission; sa02 1397; Body=1 Fuz1=1 Fuz2=1 X-Spam-Combo: *;Andrew Morton X-Spam-Relay-Country: X-Spam-Timing: total 794 ms - load_scoreonly_sql: 0.03 (0.0%), signal_user_changed: 4.3 (0.5%), b_tie_ro: 2.9 (0.4%), parse: 1.56 (0.2%), extract_message_metadata: 14 (1.7%), get_uri_detail_list: 5 (0.6%), tests_pri_-2000: 11 (1.4%), tests_pri_-1000: 1.99 (0.3%), tests_pri_-950: 1.11 (0.1%), tests_pri_-900: 0.81 (0.1%), tests_pri_-90: 64 (8.1%), check_bayes: 63 (8.0%), b_tokenize: 13 (1.6%), b_tok_get_all: 12 (1.5%), b_comp_prob: 3.0 (0.4%), b_tok_touch_all: 32 (4.1%), b_finish: 0.73 (0.1%), tests_pri_0: 682 (86.0%), check_dkim_signature: 0.49 (0.1%), check_dkim_adsp: 3.2 (0.4%), poll_dns_idle: 1.81 (0.2%), tests_pri_10: 1.75 (0.2%), tests_pri_500: 7 (0.9%), rewrite_mail: 0.00 (0.0%) Subject: [PATCH 04/11] signal: Move stopping for the coredump from do_exit into get_signal X-SA-Exim-Connect-IP: 166.70.13.51 X-SA-Exim-Rcpt-To: oleg@redhat.com, linux-kernel@vger.kernel.org, wad@chromium.org, tglx@kernel.org, peterz@infradead.org, kusaram@devineni.in, kees@kernel.org, luto@kernel.org, akpm@linux-foundation.org X-SA-Exim-Mail-From: ebiederm@xmission.com X-SA-Exim-Scanned: No (on out02.mta.xmission.com); SAEximRunCond expanded to false Stopping to participate in a coredump from a kernel oops makes no sense and is actively dangerous because the kernel is known to be broken. Considering to stop in a coredump from a kernel thread exit is silly because userspace coredumps are not generated from kernel threads. Not stopping for a coredump in exit(2) and exit_group(2) and related userspace exits that call do_exit or do_group_exit directly is the current behavior of the code as the PF_SIGNALED test in coredump_task_exit attests. Since only tasks that pass through get_signal and set PF_SIGNALED can join coredumps move stopping for coredumps into get_signal, where the PF_SIGNALED test is unnecessary. This avoids even the potential of stopping for coredumps in the silly or dangerous places. This can be seen to be safe by examining the few places that call do_exit: - get_signal calling do_group_exit Called by get_signal to terminate the userspace process. As stopping for the coredump happens now happens in get_signal the code will continue to participate in the coredump. - exit_group(2) calling do_group_exit If a thread calls exit_group(2) while another thread in the same process is performing a coredump there is a race. The thread that wins the race will take the lock and set SIGNAL_GROUP_EXIT. If it is the thread that called do_group_exit then zap_threads will return -EAGAIN and no coredump will be generated. If it is the thread that is coredumping that wins the race, the task that called do_group_exit will exit gracefully with an error code before the coredump begins. Having a single thread exit just before the coredump starts is not ideal as the semantics make no sense. (Did the group exit happen before the coredump or did the coredump happen before the group exit?). Eventually I intend for group exits to flow through get_signal and this silliness will no longer be possible. Until then the current behavior when this race occurs is maintained. - io_uring Called after get_signal returns to terminate the I/O worker thread (essentially a userspace thread that only runs kernel code) so that additional cleanup code can be run before do_exit. As get_signal is called the prior to do_exit code will continue to participate in the coredump. - make_task_dead Called on an unhandled kernel or hardware failure. As the failure is unhandled any extra work has the potential to make the failure worse so being part of a coredump is not appropriate. - kthread_exit Called to terminate a kernel thread as such coredumps do not exist. - call_usermodehelper_exec_async Called to terminate a kernel thread if kerenel_execve fails, as it is a kernel thread coredumps do not exist. - reboot, seeccomp For these calls of do_exit() they are semantically direct calls of exit(2) today. As do_exit() does not synchronize with siglock there is no logical race between a coredump killing the thread and these threads exiting. These threads logically exit before the coredump happens. This is also the current behavior so there is nothing to be concerned about with respect to userspsace semantics or regresssions. Moving the coredump stop for userspace threads that did not dequeue the coredumping signal from from do_exit into get_signal in general is safe, because the coredump in the single threaded case completely happens in get_signal. The code movement ensures that a multi-threaded coredump will not have any issues because the additional threads stop after some amount of cleanup has been done. The coredump code is robust to all kinds of userspace changes happening in parallel as multiple processes can share a mm. This makes the it safe to perform the coredump before the io_uring cleanup happens as io_uring can't do anything another process sharing the mm would not be doing. Signed-off-by: "Eric W. Biederman" --- fs/coredump.c | 25 ++++++++++++++++++++++++- include/linux/coredump.h | 2 ++ kernel/exit.c | 35 +++++++---------------------------- kernel/signal.c | 5 +++++ mm/oom_kill.c | 2 +- 5 files changed, 39 insertions(+), 30 deletions(-) diff --git a/fs/coredump.c b/fs/coredump.c index bb6fdb1f458e..96801792a80e 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -521,6 +521,29 @@ static int zap_threads(struct task_struct *tsk, return nr; } +void coredump_join(struct core_state *core_state) +{ + /* Stop and join the in-progress coredump */ + struct core_thread self; + + self.task = current; + self.next = xchg(&core_state->dumper.next, &self); + /* + * Implies mb(), the result of xchg() must be visible + * to core_state->dumper. + */ + if (atomic_dec_and_test(&core_state->nr_threads)) + complete(&core_state->startup); + + for (;;) { + set_current_state(TASK_IDLE|TASK_FREEZABLE); + if (!self.task) /* see coredump_finish() */ + break; + schedule(); + } + __set_current_state(TASK_RUNNING); +} + static int coredump_wait(int exit_code, struct core_state *core_state) { struct task_struct *tsk = current; @@ -567,7 +590,7 @@ static void coredump_finish(bool core_dumped) next = curr->next; task = curr->task; /* - * see coredump_task_exit(), curr->task must not see + * see coredump_join(), curr->task must not see * ->task == NULL before we read ->next. */ smp_mb(); diff --git a/include/linux/coredump.h b/include/linux/coredump.h index 68861da4cf7c..c183c95f9063 100644 --- a/include/linux/coredump.h +++ b/include/linux/coredump.h @@ -43,6 +43,7 @@ extern int dump_emit(struct coredump_params *cprm, const void *addr, int nr); extern int dump_align(struct coredump_params *cprm, int align); int dump_user_range(struct coredump_params *cprm, unsigned long start, unsigned long len); +extern void coredump_join(struct core_state *core_state); extern void vfs_coredump(const kernel_siginfo_t *siginfo); /* @@ -63,6 +64,7 @@ extern void vfs_coredump(const kernel_siginfo_t *siginfo); #define coredump_report_failure(fmt, ...) __COREDUMP_PRINTK(KERN_WARNING, fmt, ##__VA_ARGS__) #else +extern inline void coredump_join(struct core_state *core_state) {} static inline void vfs_coredump(const kernel_siginfo_t *siginfo) {} #define coredump_report(...) diff --git a/kernel/exit.c b/kernel/exit.c index 4bfecf2a510d..20dfa8b2101f 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -421,32 +421,6 @@ kill_orphaned_pgrp(struct task_struct *tsk, struct task_struct *parent) } } -static void coredump_task_exit(struct task_struct *tsk, - struct core_state *core_state) -{ - struct core_thread self; - - self.task = tsk; - if (self.task->flags & PF_SIGNALED) - self.next = xchg(&core_state->dumper.next, &self); - else - self.task = NULL; - /* - * Implies mb(), the result of xchg() must be visible - * to core_state->dumper. - */ - if (atomic_dec_and_test(&core_state->nr_threads)) - complete(&core_state->startup); - - for (;;) { - set_current_state(TASK_IDLE|TASK_FREEZABLE); - if (!self.task) /* see coredump_finish() */ - break; - schedule(); - } - __set_current_state(TASK_RUNNING); -} - #ifdef CONFIG_MEMCG /* drops tasklist_lock if succeeds */ static bool __try_to_set_owner(struct task_struct *tsk, struct mm_struct *mm) @@ -889,8 +863,13 @@ static void synchronize_group_exit(struct task_struct *tsk, long code) core_state = signal->core_state; spin_unlock_irq(&sighand->siglock); - if (unlikely(core_state)) - coredump_task_exit(tsk, core_state); + /* + * Decrement ->nr_threads and possibly complete + * core_state->startup to politely skip participating in any + * pending coredumps. + */ + if (unlikely(core_state) && atomic_dec_and_test(&core_state->nr_threads)) + complete(&core_state->startup); } void __noreturn do_exit(long code) diff --git a/kernel/signal.c b/kernel/signal.c index d111b779cbdb..c211b520982f 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2864,6 +2864,7 @@ bool get_signal(struct ksignal *ksig) for (;;) { bool group_exit_needed = false; + struct core_state *core_state; struct k_sigaction *ka; enum pid_type type; int exit_code = 0; @@ -3022,6 +3023,7 @@ bool get_signal(struct ksignal *ksig) } } fatal: + core_state = signal->core_state; spin_unlock_irq(&sighand->siglock); if (unlikely(cgroup_task_frozen(current))) cgroup_leave_frozen(true); @@ -3041,6 +3043,9 @@ bool get_signal(struct ksignal *ksig) * that value and ignore the one we pass it. */ vfs_coredump(&ksig->info); + } else if (core_state) { + /* Wait for the coredump to happen */ + coredump_join(core_state); } /* diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 5f372f6e26fa..ff9d59963561 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -840,7 +840,7 @@ static inline bool __task_will_free_mem(struct task_struct *task) /* * A coredumping process may sleep for an extended period in - * coredump_task_exit(), so the oom killer cannot assume that + * get_signal(), so the oom killer cannot assume that * the process will promptly exit and release memory. */ if (sig->core_state) -- 2.41.0