* [PATCH v3 1/4] arm64/gcs: release GCS on failed fork
[not found] <20261028154315.1272705-1-ivanrwcm25@gmail.com>
@ 2026-10-28 15:43 ` Iván Ezequiel Rodriguez
2026-10-28 18:41 ` Mark Brown
2026-10-29 20:32 ` Catalin Marinas
2026-10-28 15:43 ` [PATCH v3 2/4] riscv/shstk: release shadow stack " Iván Ezequiel Rodriguez
1 sibling, 2 replies; 5+ messages in thread
From: Iván Ezequiel Rodriguez @ 2026-10-28 15:43 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Paul Walmsley, Palmer Dabbelt,
linux-arm-kernel, linux-riscv
Cc: linux-kernel, linux-kselftest, Mark Rutland, Mark Brown,
Deepak Gupta, Alexandre Ghiti, Albert Ou, Shuah Khan,
Christian Brauner, James Morse, Yury Khrustalev,
Thiago Jung Bauermann, Samuel Holland, Zong Li, Charlie Jenkins,
Shaopeng Tan, Zishun Yi, Peter Zijlstra (Intel), stable
copy_thread() can map a CLONE_VM GCS and still return 0. A later
copy_process() failure calls exit_thread(), but arm64 did not
implement it, so the VMA stayed in the parent's mm. Wire
HAVE_EXIT_THREAD to gcs_free().
x86 already does this via exit_thread() -> shstk_free(). The separate
x86 TLS leak is different: copy_thread() itself fails after the
alloc, so copy_process() skips exit_thread().
args->fn tasks inherit GCS tracking without allocating; clear it so
a failed CLONE_VM copy_process() cannot gcs_free() the caller's
stack. Keep that helper in process.c with the other fork helpers.
Fixes: 506496bcbb42 ("arm64/gcs: Ensure that new threads have a GCS")
Cc: stable@vger.kernel.org
Cc: Mark Brown <broonie@kernel.org>
Assisted-by: LLM
Signed-off-by: Iván Ezequiel Rodriguez <ivanrwcm25@gmail.com>
---
arch/arm64/Kconfig | 1 +
arch/arm64/kernel/process.c | 16 ++++++++++++++++
2 files changed, 17 insertions(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index cfef22aee709..3010ced4b4f2 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -177,6 +177,7 @@ config ARM64
select HAVE_ARM_SMCCC
select HAVE_ASM_MODVERSIONS
select HAVE_EBPF_JIT
+ select HAVE_EXIT_THREAD
select HAVE_C_RECORDMCOUNT
select HAVE_CMPXCHG_DOUBLE
select HAVE_CMPXCHG_LOCAL
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 581f80e9b9b7..d17172e60acb 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -320,6 +320,13 @@ static int copy_thread_gcs(struct task_struct *p,
return 0;
}
+static void gcs_reset_thread(struct task_struct *task)
+{
+ task->thread.gcs_base = 0;
+ task->thread.gcs_size = 0;
+ task->thread.gcspr_el0 = 0;
+}
+
#else
static void flush_gcs(void) { }
@@ -328,6 +335,7 @@ static int copy_thread_gcs(struct task_struct *p,
{
return 0;
}
+static void gcs_reset_thread(struct task_struct *task) { }
#endif
@@ -341,6 +349,12 @@ void flush_thread(void)
flush_gcs();
}
+void exit_thread(struct task_struct *tsk)
+{
+ /* Failed fork after copy_thread(); deactivate_mm() does not run. */
+ gcs_free(tsk);
+}
+
void arch_release_task_struct(struct task_struct *tsk)
{
fpsimd_release_task(tsk);
@@ -503,6 +517,8 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
p->thread.cpu_context.x19 = (unsigned long)args->fn;
p->thread.cpu_context.x20 = (unsigned long)args->fn_arg;
+ /* No user GCS alloc here; drop inherited tracking for CLONE_VM. */
+ gcs_reset_thread(p);
if (system_supports_poe())
p->thread.por_el0 = POR_EL0_INIT;
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v3 2/4] riscv/shstk: release shadow stack on failed fork
[not found] <20261028154315.1272705-1-ivanrwcm25@gmail.com>
2026-10-28 15:43 ` [PATCH v3 1/4] arm64/gcs: release GCS on failed fork Iván Ezequiel Rodriguez
@ 2026-10-28 15:43 ` Iván Ezequiel Rodriguez
1 sibling, 0 replies; 5+ messages in thread
From: Iván Ezequiel Rodriguez @ 2026-10-28 15:43 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Paul Walmsley, Palmer Dabbelt,
linux-arm-kernel, linux-riscv
Cc: linux-kernel, linux-kselftest, Mark Rutland, Mark Brown,
Deepak Gupta, Alexandre Ghiti, Albert Ou, Shuah Khan,
Christian Brauner, James Morse, Yury Khrustalev,
Thiago Jung Bauermann, Samuel Holland, Zong Li, Charlie Jenkins,
Shaopeng Tan, Zishun Yi, Peter Zijlstra (Intel), stable
Same hole as arm64: copy_thread() maps a CLONE_VM shadow stack,
copy_process() fails later, exit_thread() ran but was never
implemented. Select HAVE_EXIT_THREAD and call shstk_release().
shstk_release() already documented this path; connect it. Clear
inherited tracking on the args->fn path for the same CLONE_VM
reason as arm64.
Fixes: fd44a4a85516 ("riscv/shstk: If needed allocate a new shadow stack on clone")
Cc: stable@vger.kernel.org
Cc: Deepak Gupta <debug@rivosinc.com>
Assisted-by: LLM
Signed-off-by: Iván Ezequiel Rodriguez <ivanrwcm25@gmail.com>
---
arch/riscv/Kconfig | 1 +
arch/riscv/kernel/process.c | 9 +++++++++
2 files changed, 10 insertions(+)
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 6c9d61d83d71..ba1ee563aa54 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -168,6 +168,7 @@ config RISCV
select HAVE_FUNCTION_GRAPH_FREGS
select HAVE_FUNCTION_TRACER if HAVE_DYNAMIC_FTRACE
select HAVE_EBPF_JIT if MMU
+ select HAVE_EXIT_THREAD
select HAVE_GENERIC_TIF_BITS
select HAVE_GUP_FAST if MMU
select HAVE_FUNCTION_ARG_ACCESS_API
diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
index 7cc5a6a5c020..5bb93377d67f 100644
--- a/arch/riscv/kernel/process.c
+++ b/arch/riscv/kernel/process.c
@@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/sched/debug.h>
+#include <linux/sched/task.h>
#include <linux/sched/task_stack.h>
#include <linux/tick.h>
#include <linux/ptrace.h>
@@ -213,6 +214,12 @@ void arch_release_task_struct(struct task_struct *tsk)
riscv_v_thread_free(tsk);
}
+void exit_thread(struct task_struct *tsk)
+{
+ /* Failed fork after copy_thread(); deactivate_mm() does not run. */
+ shstk_release(tsk);
+}
+
int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
{
fstate_save(src, task_pt_regs(src));
@@ -261,6 +268,8 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
p->thread.s[0] = (unsigned long)args->fn;
p->thread.s[1] = (unsigned long)args->fn_arg;
p->thread.ra = (unsigned long)ret_from_fork_kernel_asm;
+ /* No user shstk alloc here; drop inherited tracking for CLONE_VM. */
+ set_shstk_base(p, 0, 0);
} else {
/* allocate new shadow stack if needed. In case of CLONE_VM we have to */
ssp = shstk_alloc_thread_stack(p, args);
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v3 1/4] arm64/gcs: release GCS on failed fork
2026-10-28 15:43 ` [PATCH v3 1/4] arm64/gcs: release GCS on failed fork Iván Ezequiel Rodriguez
@ 2026-10-28 18:41 ` Mark Brown
2026-10-29 20:32 ` Catalin Marinas
1 sibling, 0 replies; 5+ messages in thread
From: Mark Brown @ 2026-10-28 18:41 UTC (permalink / raw)
To: Iván Ezequiel Rodriguez
Cc: Catalin Marinas, Will Deacon, Paul Walmsley, Palmer Dabbelt,
linux-arm-kernel, linux-riscv, linux-kernel, linux-kselftest,
Mark Rutland, Deepak Gupta, Alexandre Ghiti, Albert Ou,
Shuah Khan, Christian Brauner, James Morse, Yury Khrustalev,
Thiago Jung Bauermann, Samuel Holland, Zong Li, Charlie Jenkins,
Shaopeng Tan, Zishun Yi, Peter Zijlstra (Intel), stable
[-- Attachment #1: Type: text/plain, Size: 959 bytes --]
On Wed, Oct 28, 2026 at 12:43:12PM -0300, Iván Ezequiel Rodriguez wrote:
> copy_thread() can map a CLONE_VM GCS and still return 0. A later
> copy_process() failure calls exit_thread(), but arm64 did not
> implement it, so the VMA stayed in the parent's mm. Wire
> HAVE_EXIT_THREAD to gcs_free().
One extremely minor nit below, I verified that this fails with the
current kernel and that the kernel change causes it to pass so with or
without dealing with that:
Reviewed-by: Mark Brown <broonie@kernel.org>
Tested-by: Mark Brown <broonie@kernel.org>
> @@ -328,6 +335,7 @@ static int copy_thread_gcs(struct task_struct *p,
> {
> return 0;
> }
> +static void gcs_reset_thread(struct task_struct *task) { }
>
This looks like there's a missing blank line but it fits in with the
missing blank before the stub for copy_thread_gcs(). Possibly slightly
neater to put this before there next to the similar flush_gcs() stub but
meh.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v3 1/4] arm64/gcs: release GCS on failed fork
2026-10-28 15:43 ` [PATCH v3 1/4] arm64/gcs: release GCS on failed fork Iván Ezequiel Rodriguez
2026-10-28 18:41 ` Mark Brown
@ 2026-10-29 20:32 ` Catalin Marinas
2026-10-29 22:36 ` Mark Brown
1 sibling, 1 reply; 5+ messages in thread
From: Catalin Marinas @ 2026-10-29 20:32 UTC (permalink / raw)
To: Iván Ezequiel Rodriguez
Cc: Will Deacon, Paul Walmsley, Palmer Dabbelt, linux-arm-kernel,
linux-riscv, linux-kernel, linux-kselftest, Mark Rutland,
Mark Brown, Deepak Gupta, Alexandre Ghiti, Albert Ou, Shuah Khan,
Christian Brauner, James Morse, Yury Khrustalev,
Thiago Jung Bauermann, Samuel Holland, Zong Li, Charlie Jenkins,
Shaopeng Tan, Zishun Yi, Peter Zijlstra (Intel), stable
On Wed, Oct 28, 2026 at 12:43:12PM -0300, Iván Ezequiel Rodriguez wrote:
> copy_thread() can map a CLONE_VM GCS and still return 0. A later
> copy_process() failure calls exit_thread(), but arm64 did not
> implement it, so the VMA stayed in the parent's mm. Wire
> HAVE_EXIT_THREAD to gcs_free().
>
> x86 already does this via exit_thread() -> shstk_free(). The separate
> x86 TLS leak is different: copy_thread() itself fails after the
> alloc, so copy_process() skips exit_thread().
Is the x86 TLS leak relevant to arm64?
[...]
> @@ -503,6 +517,8 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
>
> p->thread.cpu_context.x19 = (unsigned long)args->fn;
> p->thread.cpu_context.x20 = (unsigned long)args->fn_arg;
> + /* No user GCS alloc here; drop inherited tracking for CLONE_VM. */
> + gcs_reset_thread(p);
My LLM run noticed that this fixes another problem, unrelated to the
failed fork: io_uring and vhost workers are created with args->fn and
CLONE_VM and they inherit gcs_base/gcs_size from the creating task
through arch_dup_task_struct(). Without this reset, a worker exiting
normally unmaps the parent task's GCS.
I was wondering whether to have a separate one-line commit for the
worker thread case but I think I'll just add a comment in the commit
log, keep things simple.
--
Catalin
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v3 1/4] arm64/gcs: release GCS on failed fork
2026-10-29 20:32 ` Catalin Marinas
@ 2026-10-29 22:36 ` Mark Brown
0 siblings, 0 replies; 5+ messages in thread
From: Mark Brown @ 2026-10-29 22:36 UTC (permalink / raw)
To: Catalin Marinas
Cc: Iván Ezequiel Rodriguez, Will Deacon, Paul Walmsley,
Palmer Dabbelt, linux-arm-kernel, linux-riscv, linux-kernel,
linux-kselftest, Mark Rutland, Deepak Gupta, Alexandre Ghiti,
Albert Ou, Shuah Khan, Christian Brauner, James Morse,
Yury Khrustalev, Thiago Jung Bauermann, Samuel Holland, Zong Li,
Charlie Jenkins, Shaopeng Tan, Zishun Yi, Peter Zijlstra (Intel),
stable
[-- Attachment #1: Type: text/plain, Size: 472 bytes --]
On Thu, Oct 29, 2026 at 08:32:30PM +0000, Catalin Marinas wrote:
> On Wed, Oct 28, 2026 at 12:43:12PM -0300, Iván Ezequiel Rodriguez wrote:
> > x86 already does this via exit_thread() -> shstk_free(). The separate
> > x86 TLS leak is different: copy_thread() itself fails after the
> > alloc, so copy_process() skips exit_thread().
> Is the x86 TLS leak relevant to arm64?
That was in response to me querying if they were affected on prior
versions I think.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-10-29 22:36 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20261028154315.1272705-1-ivanrwcm25@gmail.com>
2026-10-28 15:43 ` [PATCH v3 1/4] arm64/gcs: release GCS on failed fork Iván Ezequiel Rodriguez
2026-10-28 18:41 ` Mark Brown
2026-10-29 20:32 ` Catalin Marinas
2026-10-29 22:36 ` Mark Brown
2026-10-28 15:43 ` [PATCH v3 2/4] riscv/shstk: release shadow stack " Iván Ezequiel Rodriguez
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox