From: "Iván Ezequiel Rodriguez" <ivanrwcm25@gmail.com>
To: Catalin Marinas <catalin.marinas@arm.com>,
Will Deacon <will@kernel.org>, Paul Walmsley <pjw@kernel.org>,
Palmer Dabbelt <palmer@dabbelt.com>,
linux-arm-kernel@lists.infradead.org,
linux-riscv@lists.infradead.org
Cc: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org,
Mark Rutland <mark.rutland@arm.com>,
Mark Brown <broonie@kernel.org>,
Deepak Gupta <debug@rivosinc.com>,
Alexandre Ghiti <alex@ghiti.fr>,
Albert Ou <aou@eecs.berkeley.edu>, Shuah Khan <shuah@kernel.org>,
Christian Brauner <brauner@kernel.org>,
James Morse <james.morse@arm.com>,
Yury Khrustalev <yury.khrustalev@arm.com>,
Thiago Jung Bauermann <thiago.bauermann@linaro.org>,
Samuel Holland <samuel.holland@sifive.com>,
Zong Li <zong.li@sifive.com>,
Charlie Jenkins <thecharlesjenkins@gmail.com>,
Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>,
Zishun Yi <vulab@iscas.ac.cn>,
"Peter Zijlstra (Intel)" <peterz@infradead.org>,
stable@vger.kernel.org
Subject: [PATCH v2 1/4] arm64/gcs: release GCS on failed fork
Date: Tue, 20 Oct 2026 15:19:30 -0300 [thread overview]
Message-ID: <8522b8d3d3ecda7474d0af8b8517c1f5d708ecc2.1792519121.git.ivanrwcm25@gmail.com> (raw)
In-Reply-To: <cover.1792519121.git.ivanrwcm25@gmail.com>
copy_thread() maps a GCS for a CLONE_VM child and can still return
0. A later copy_process() failure then goes through
bad_fork_cleanup_thread, which calls exit_thread(). The hole this
series hits is clone3(CLONE_VM|CLONE_PIDFD) when put_user() of the
pidfd fails after that mapping. arm64 did not implement
exit_thread(). deactivate_mm() is what normally calls gcs_free(),
and it does not run on this path. Each rejected clone leaves one
GCS VMA in the parent's mm until the mm dies.
Select HAVE_EXIT_THREAD and free the child's GCS from
exit_thread(). gcs_free() already ignores a cleared base and a
different mm, so the usual exit path (deactivate_mm() then this) is
a no-op the second time. copy_thread_gcs() zeros the inherited
tracking before a user-thread allocation, so an allocation error
still skips exit_thread() with nothing to unmap.
Tasks created through the args->fn path (kernel_thread(),
create_io_thread(), and similar) do not allocate a user GCS in
copy_thread(). They still inherit GCS tracking via
arch_dup_task_struct(), and with CLONE_VM a later failed
copy_process() still shares the caller's mm, so gcs_free()'s mm
check does not save us. Clear that tracking with
gcs_reset_thread(), an empty stub when !CONFIG_ARM64_GCS.
x86 does not need the same args->fn clear: copy_thread() runs
shstk_alloc_thread_stack() before both the PF_KTHREAD and later
args->fn return paths, so CLONE_VM replaces the inherited tracking
first.
Tested with CONFIG_ARM64_GCS on QEMU 11.1.2 -machine virt -cpu max.
Sixteen clone3() calls with CLONE_VM|CLONE_PIDFD and an unwritable
pidfd pointer leaked 16 GCS VMAs without the fix. With it, the VMA
count was unchanged.
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/include/asm/gcs.h | 8 ++++++++
arch/arm64/kernel/process.c | 19 +++++++++++++++++++
3 files changed, 28 insertions(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index cab741a695f5..c7fc79409f98 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/include/asm/gcs.h b/arch/arm64/include/asm/gcs.h
index 8fa0707069e8..f47aaad30d7d 100644
--- a/arch/arm64/include/asm/gcs.h
+++ b/arch/arm64/include/asm/gcs.h
@@ -67,6 +67,13 @@ void gcs_preserve_current_state(void);
unsigned long gcs_alloc_thread_stack(struct task_struct *tsk,
const struct kernel_clone_args *args);
+static inline void gcs_reset_thread(struct task_struct *task)
+{
+ task->thread.gcs_base = 0;
+ task->thread.gcs_size = 0;
+ task->thread.gcspr_el0 = 0;
+}
+
static inline int gcs_check_locked(struct task_struct *task,
unsigned long new_val)
{
@@ -167,6 +174,7 @@ static inline bool task_gcs_el0_enabled(struct task_struct *task)
static inline void gcs_set_el0_mode(struct task_struct *task) { }
static inline void gcs_free(struct task_struct *task) { }
static inline void gcs_preserve_current_state(void) { }
+static inline void gcs_reset_thread(struct task_struct *task) { }
static inline void put_user_gcs(unsigned long val, unsigned long __user *addr,
int *err) { }
static inline void push_user_gcs(unsigned long val, int *err) { }
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 581f80e9b9b7..83d5a07a238f 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -341,6 +341,16 @@ void flush_thread(void)
flush_gcs();
}
+void exit_thread(struct task_struct *tsk)
+{
+ /*
+ * copy_process() calls this after copy_thread() returns 0.
+ * deactivate_mm() does not run on that failure path.
+ * gcs_free() is a no-op once gcs_base is cleared.
+ */
+ gcs_free(tsk);
+}
+
void arch_release_task_struct(struct task_struct *tsk)
{
fpsimd_release_task(tsk);
@@ -503,6 +513,15 @@ 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;
+ /*
+ * Tasks created through the args->fn path do not
+ * allocate a user GCS here. Clear inherited allocation
+ * tracking so a later failed copy_process() cannot
+ * release the caller's GCS when the mm is still shared
+ * (CLONE_VM), as with kernel_thread() and
+ * create_io_thread().
+ */
+ gcs_reset_thread(p);
if (system_supports_poe())
p->thread.por_el0 = POR_EL0_INIT;
--
2.43.0
next prev parent reply other threads:[~2026-10-20 18:19 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-16 19:45 [PATCH 0/4] arm64, riscv: release shadow stacks " Iván Ezequiel Rodriguez
2026-10-16 19:46 ` [PATCH 1/4] arm64/gcs: release GCS " Iván Ezequiel Rodriguez
2026-10-20 12:05 ` Mark Brown
2026-10-16 19:46 ` [PATCH 2/4] riscv/shstk: release shadow stack " Iván Ezequiel Rodriguez
2026-10-16 19:46 ` [PATCH 3/4] selftests/arm64: GCS must not leak on a failed clone3 Iván Ezequiel Rodriguez
2026-10-20 15:16 ` Mark Brown
2026-10-16 19:46 ` [PATCH 4/4] selftests/riscv: shadow stack " Iván Ezequiel Rodriguez
2026-10-20 18:19 ` [PATCH v2 0/4] arm64, riscv: release shadow stacks on failed fork Iván Ezequiel Rodriguez
2026-10-20 18:19 ` Iván Ezequiel Rodriguez [this message]
2026-10-20 18:19 ` [PATCH v2 2/4] riscv/shstk: release shadow stack " Iván Ezequiel Rodriguez
2026-10-20 18:19 ` [PATCH v2 3/4] selftests/arm64: GCS must not leak on a failed clone3 Iván Ezequiel Rodriguez
2026-10-20 18:19 ` [PATCH v2 4/4] selftests/riscv: shadow stack " Iván Ezequiel Rodriguez
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8522b8d3d3ecda7474d0af8b8517c1f5d708ecc2.1792519121.git.ivanrwcm25@gmail.com \
--to=ivanrwcm25@gmail.com \
--cc=alex@ghiti.fr \
--cc=aou@eecs.berkeley.edu \
--cc=brauner@kernel.org \
--cc=broonie@kernel.org \
--cc=catalin.marinas@arm.com \
--cc=debug@rivosinc.com \
--cc=james.morse@arm.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=mark.rutland@arm.com \
--cc=palmer@dabbelt.com \
--cc=peterz@infradead.org \
--cc=pjw@kernel.org \
--cc=samuel.holland@sifive.com \
--cc=shuah@kernel.org \
--cc=stable@vger.kernel.org \
--cc=tan.shaopeng@jp.fujitsu.com \
--cc=thecharlesjenkins@gmail.com \
--cc=thiago.bauermann@linaro.org \
--cc=vulab@iscas.ac.cn \
--cc=will@kernel.org \
--cc=yury.khrustalev@arm.com \
--cc=zong.li@sifive.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®