From nobody Sat Jul 25 18:53:04 2026 Received: from confino.investici.org (confino.investici.org [93.190.126.19]) (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 BC2712F747A; Tue, 14 Jul 2026 17:31:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=93.190.126.19 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784050277; cv=none; b=LLBo7cp4EJs9KgeMpxFrKa8jfF13x4+9u13ESX4ZfMz52fWsy1hEV08xRtDlcimiJVqJEEf8KMXgnw8GdArbLTj2WarBERz2fdXsdVZkUTt+aels1yucGSw+Vqh4xaTjIlV0ngt4MS621HLtzyV4aHBjgTtF+SnxzVksfX0lZh4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784050277; c=relaxed/simple; bh=w1mYjv8GbbGlh4L3ZkV5ZAOlY2kZDkhvdzF2MV31uXg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=aS6e5/rJbXRu7m+os1dCGqF9Z8V0B4MDdWSXwD86eY3cEOWEc6Dy1h/oQ1vvcUggPOiJOGVhpQ1TJnaNG5tbo+9IZmtaouSV/wtcuAT+NhgEu90YwVW9NJrUt9GhyME94hp9WHc/FdQGSr0ybHT27CBh0CiJ9iNtV9lnzQ27+9Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=grrlz.net; spf=pass smtp.mailfrom=grrlz.net; dkim=pass (1024-bit key) header.d=grrlz.net header.i=@grrlz.net header.b=dsC0w/N4; arc=none smtp.client-ip=93.190.126.19 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=grrlz.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=grrlz.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=grrlz.net header.i=@grrlz.net header.b="dsC0w/N4" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=grrlz.net; s=stigmate; t=1784050272; bh=VSvZ2YmFYJgswAHCUCoQI7VB4pGV7FI8gD3I7LgNYB4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dsC0w/N4Hi+6pNWEqkFywPQuy3K8QsIArIpcpKexwqPotzSlpzuPrXV0off1wwd2o cd/mViiRY4yO19hC1CmGF4T/Sv+i+3IiPSwcm8apt2Ggibo3V0spN4e+j40DDCyrCG jn4Xr5motEY2HDi117gJfamSJpXUWqNwJPTjVC5k= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4h05v42Zg7z112m; Tue, 14 Jul 2026 17:31:12 +0000 (UTC) Received: by mx1.investici.org (Postfix) id 4h05v263L3z112c; Tue, 14 Jul 2026 17:31:10 +0000 (UTC) From: Bradley Morgan To: akpm@linux-foundation.org Cc: pmladek@suse.com, feng.tang@linux.alibaba.com, sashiko-bot@kernel.org, stable@vger.kernel.org, linux-kernel@vger.kernel.org, include@grrlz.net Subject: [PATCH v4 1/3] panic: fix redirect CPU race in panic_try_force_cpu() Date: Tue, 14 Jul 2026 17:31:00 +0000 Message-ID: <20260714173103.11585-2-include@grrlz.net> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260714173103.11585-1-include@grrlz.net> References: <20260714173103.11585-1-include@grrlz.net> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The cmpxchg() in panic_try_force_cpu() makes sure that only one CPU tries to redirect panic() to the requested CPU. It is similar to the cmpxchg() in panic_try_start() which makes sure that only one CPU does the panic(). In both situations, only the winner of cmpxchg() should proceed further. Other CPUs should go offline. There is a bug because the cmpxchg loser returns false and falls through into vpanic(). Two non-target CPUs A and B panic, the requested CPU is C: cpu A cpu B ---------- ---------- panic() panic() vpanic() vpanic() panic_try_force_cpu() panic_try_force_cpu() cmpxchg wins cmpxchg fails redirect =3D A old_cpu =3D A IPI -> C return false <- BUG return true panic_try_start() wins panic_smp_self_stop() __crash_kexec() on B (A stops) (target C bypassed) The loser must stop, not fall through. It cannot just return true, though. A CPU that already won the redirect cmpxchg can reenter panic_try_force_cpu() on the same CPU, for example a nested NMI during the message formatting, before the IPI is sent: cpu A (1st) cpu A (nested) ---------- ---------- panic() vpanic() panic_try_force_cpu() cmpxchg wins (redirect =3D A) vsnprintf(msg) ... <-- NMI, nested panic --> panic() vpanic() panic_try_force_cpu() cmpxchg fails old_cpu =3D=3D A (this CPU) return true <- would halt panic_smp_self_stop() (IPI never sent, panic abandoned) Check old_cpu against this_cpu so a second call from the same CPU returns false and falls through to panic_try_start() instead. Also fix the panic_in_progress() check. We must not redirect when panic_cpu is already assigned. Return true to stop when the panic is on another CPU, false to proceed when it is this one. Reported-by: Sashiko Closes: https://sashiko.dev/#/patchset/20260705164123.18746-1-include@grrlz= .net Closes: https://sashiko.dev/#/patchset/20260707172252.4842-1-include@grrlz.= net Cc: stable@vger.kernel.org Signed-off-by: Bradley Morgan Reviewed-by: Petr Mladek --- kernel/panic.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/kernel/panic.c b/kernel/panic.c index 03f1eef07b17..4b1de407a73a 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -396,16 +396,20 @@ static bool panic_try_force_cpu(const char *fmt, va_l= ist args) return false; } =20 - /* Another panic already in progress */ + /* + * Don't redirect when a panic is already in progress. Stop this + * CPU when it's another one, proceed when it's this one. + */ if (panic_in_progress()) - return false; + return !panic_on_this_cpu(); =20 /* - * Only one CPU can do the redirect. Use atomic cmpxchg to ensure - * we don't race with another CPU also trying to redirect. + * Only one CPU can do the redirection. Others should go offline. + * Continue with panic() when we already tried the redirection + * from this CPU before, for example via nmi_panic(). */ if (!atomic_try_cmpxchg(&panic_redirect_cpu, &old_cpu, this_cpu)) - return false; + return old_cpu !=3D this_cpu; =20 /* * Use dynamically allocated buffer if available, otherwise --=20 2.53.0 From nobody Sat Jul 25 18:53:04 2026 Received: from confino.investici.org (confino.investici.org [93.190.126.19]) (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 C294C2EB859; Tue, 14 Jul 2026 17:31:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=93.190.126.19 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784050278; cv=none; b=Lw4zLphijZvB/BYgqMKXTCvNeWcK1Ymap/Ai91vCL+OikTgHt44XZoZupVxBmImxryMF1wngKPuC8BkOZqjow/Rrpt7SVBHuKwYd/Gxk9d4vbT6Da9b6cWY5uFppipLADRz5CjL+Jh7F0GZ0KIGGf39e5RClbm+rNtZR0WlbrWc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784050278; c=relaxed/simple; bh=SgYw+tKhY9EOguEzIGhkCJ1OXgB6PqiTM1tC1FsfDtM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JCPuLi9lzApXvryEteWg7gx8QGEdHDgTV1oqG0IEjGRyDsOBLM9MeOp/9QyBt/nZMPDVOeUubC11PpaJuqJApdnFINNyaDJY14+W2KWnaNTb+6Ivcwp1ner1FooLYymjlh6oUmvA3xr4412XVD518Okj+X39t1bkv/OeTbF/7wU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=grrlz.net; spf=pass smtp.mailfrom=grrlz.net; dkim=pass (1024-bit key) header.d=grrlz.net header.i=@grrlz.net header.b=e/KfRN7L; arc=none smtp.client-ip=93.190.126.19 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=grrlz.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=grrlz.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=grrlz.net header.i=@grrlz.net header.b="e/KfRN7L" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=grrlz.net; s=stigmate; t=1784050273; bh=rp1APUYx0TOZAKa7fp7hjDCITUt2bKcaX9BfvIPZp+Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=e/KfRN7LhkWTwOocLQqme5QzotOehwhB5QUEvEzBb4Ozy3WGbPp38oRNaaisrWm8V xLcYkuDeEDp4LzIAgyRngy54bEBDskULVCnuOKrG0soRxMmmwoPVSqe7SUx9wb5fZA JpjIuim5eQbtgy1HJiK7z1q11ARzMk37WSPMWczs= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4h05v55Vq2z112q; Tue, 14 Jul 2026 17:31:13 +0000 (UTC) Received: by mx1.investici.org (Postfix) id 4h05v43m4Hz112c; Tue, 14 Jul 2026 17:31:12 +0000 (UTC) From: Bradley Morgan To: akpm@linux-foundation.org Cc: pmladek@suse.com, feng.tang@linux.alibaba.com, sashiko-bot@kernel.org, stable@vger.kernel.org, linux-kernel@vger.kernel.org, include@grrlz.net Subject: [PATCH v4 2/3] panic: flatten nmi_panic control flow Date: Tue, 14 Jul 2026 17:31:01 +0000 Message-ID: <20260714173103.11585-3-include@grrlz.net> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260714173103.11585-1-include@grrlz.net> References: <20260714173103.11585-1-include@grrlz.net> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" panic() is __noreturn, so the else after panic_try_start() is dead. Drop it so the force_cpu path can be added cleanly on top. Signed-off-by: Bradley Morgan Reviewed-by: Petr Mladek --- kernel/panic.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/panic.c b/kernel/panic.c index 4b1de407a73a..c58c72d9f5a0 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -521,7 +521,8 @@ void nmi_panic(struct pt_regs *regs, const char *msg) { if (panic_try_start()) panic("%s", msg); - else if (panic_on_other_cpu()) + + if (panic_on_other_cpu()) nmi_panic_self_stop(regs); } EXPORT_SYMBOL(nmi_panic); --=20 2.53.0 From nobody Sat Jul 25 18:53:04 2026 Received: from confino.investici.org (confino.investici.org [93.190.126.19]) (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 61CED261388; Tue, 14 Jul 2026 17:31:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=93.190.126.19 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784050279; cv=none; b=CbTUiidZskFKsm5gjLd8ikcl4qHXSmnolS2Q/oDknsHAAFgofPk0IBMNVOt+E/aeeG/pmP6AOfIlRqyqPJefD4orpfvC+eBVpGhZivTlrUV0A3m8TDtAuchSAokHXEBX3oYZYBhZHtKSa8MRGv4/QTC96FvK5ZP3ek8X8vr1/eE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784050279; c=relaxed/simple; bh=8SRN96h3qsVItWUutJFKOI64e3eK1Au6hyeH09dAdfw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=vF/CYwIpzPu8XbY84YcNPmf0x2j8Ys29uR1RxmojXCriCjHQCVP/4e5KKO9pepfcRnoyaMhV//7Kri+C9YYK4D+sFpsbtHpn9/YWVfRgkCi2ViyrbA/dWJf5edH7Vse8naO/FITaRN9p8r9Xi0a1v9YWs90drlNfW9s0Kq+QcKw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=grrlz.net; spf=pass smtp.mailfrom=grrlz.net; dkim=pass (1024-bit key) header.d=grrlz.net header.i=@grrlz.net header.b=JCuautg8; arc=none smtp.client-ip=93.190.126.19 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=grrlz.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=grrlz.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=grrlz.net header.i=@grrlz.net header.b="JCuautg8" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=grrlz.net; s=stigmate; t=1784050274; bh=b36zf3rs7zvqc4fJ5AgCG9tOAbyeS22TKu09skdKryQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JCuautg8Zekw12m3HwplN/l5RadmCDM3dUq8m36h/q/ObUNeyXVrifVqT16IoNpgU j7I/DU3cGKc68FAtIOLgGI8/+2ZfrjpHdSZoAkA4oaLZTG54DXDRZEzhSt2Q8mseE0 hJrDR381KAfqTsIK6uX2Qth9CGWC7PJthlJ9z/Lg= Received: from mx1.investici.org (unknown [127.0.0.1]) by confino.investici.org (Postfix) with ESMTP id 4h05v65NVFz112r; Tue, 14 Jul 2026 17:31:14 +0000 (UTC) Received: by mx1.investici.org (Postfix) id 4h05v56JyXz112c; Tue, 14 Jul 2026 17:31:13 +0000 (UTC) From: Bradley Morgan To: akpm@linux-foundation.org Cc: pmladek@suse.com, feng.tang@linux.alibaba.com, sashiko-bot@kernel.org, stable@vger.kernel.org, linux-kernel@vger.kernel.org, include@grrlz.net Subject: [PATCH v4 3/3] panic: allow force_cpu redirect from an NMI Date: Tue, 14 Jul 2026 17:31:02 +0000 Message-ID: <20260714173103.11585-4-include@grrlz.net> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260714173103.11585-1-include@grrlz.net> References: <20260714173103.11585-1-include@grrlz.net> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" nmi_panic() calls panic_try_start() before panic(), so it claims panic_cpu first. When the panic then reaches panic_try_force_cpu(), the panic_in_progress() check sees panic_cpu set and returns false, so the redirect to the requested CPU never happens. The crash kernel runs on the CPU that took the NMI instead. The buggy call order, on a CPU X that is not the target (target is C): nmi_panic() panic_try_start() wins, panic_cpu =3D X panic("%s", msg) vpanic() panic_try_force_cpu() panic_in_progress() true, panic_cpu is X return false redirect bypassed panic_try_start() already won __crash_kexec() on X, not C The fix is to try the redirect before claiming panic_cpu. nmi_panic() now calls panic_try_force_cpu_fmt() first, and only calls panic_try_start() when no redirect happens. The requested CPU then claims panic_cpu itself when it runs panic(), so panic_cpu does not need to be handed off. nmi_panic() holds an already formatted string, not a va_list. Add a variadic wrapper, panic_try_force_cpu_fmt(), so it can reach the existing formatting guarded by the cmpxchg in panic_try_force_cpu() without a signature change. The wrapper builds the va_list and the real function still copies and formats under the redirect cmpxchg, so no shared buffer is written before ownership. The redirect sends the IPI via smp_call_function_single_async(). This is safe from NMI context: the doc on the _async variant states it can be called with interrupts disabled, and kgdb_roundup_cpus() already calls it from NMI/debug context (kernel/debug/debug_core.c). The nmi_panic() body is reshaped to a goto self_stop, since panic() is noreturn and the stop path is shared. Reported-by: Sashiko Closes: https://sashiko.dev/#/patchset/20260708164312.19044-1-include@grrlz= .net Cc: stable@vger.kernel.org Signed-off-by: Bradley Morgan --- kernel/panic.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/kernel/panic.c b/kernel/panic.c index c58c72d9f5a0..c81a5c9646e3 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -450,12 +450,32 @@ static bool panic_try_force_cpu(const char *fmt, va_l= ist args) /* IPI/NMI sent, this CPU should stop */ return true; } + +/* For callers without a va_list, such as nmi_panic(). */ +static __printf(1, 2) +bool panic_try_force_cpu_fmt(const char *fmt, ...) +{ + va_list args; + bool ret; + + va_start(args, fmt); + ret =3D panic_try_force_cpu(fmt, args); + va_end(args); + + return ret; +} #else __printf(1, 0) static inline bool panic_try_force_cpu(const char *fmt, va_list args) { return false; } + +static __printf(1, 2) +bool panic_try_force_cpu_fmt(const char *fmt, ...) +{ + return false; +} #endif /* CONFIG_SMP && CONFIG_CRASH_DUMP */ =20 bool panic_try_start(void) @@ -519,11 +539,20 @@ EXPORT_SYMBOL(panic_on_other_cpu); */ void nmi_panic(struct pt_regs *regs, const char *msg) { + /* Try to redirect to the requested CPU when one is set. */ + if (panic_try_force_cpu_fmt("%s", msg)) + goto self_stop; + + /* Try to acquire the right to proceed with the noreturn panic(). */ if (panic_try_start()) panic("%s", msg); =20 - if (panic_on_other_cpu()) - nmi_panic_self_stop(regs); + /* + * panic_try_start() only fails when a panic is already in progress + * on another CPU, in which case this CPU must stop. + */ +self_stop: + nmi_panic_self_stop(regs); } EXPORT_SYMBOL(nmi_panic); =20 --=20 2.53.0