From: Mark Brown <broonie@kernel.org>
To: Catalin Marinas <catalin.marinas@arm.com>,
Will Deacon <will@kernel.org>,
Christian Brauner <brauner@kernel.org>,
Adhemerval Zanella Netto <adhemerval.zanella@linaro.org>,
Shuah Khan <shuah@kernel.org>
Cc: Rick Edgecombe <rick.p.edgecombe@intel.com>,
Deepak Gupta <debug@rivosinc.com>,
Wilco Dijkstra <wilco.dijkstra@arm.com>,
Carlos O'Donell <codonell@redhat.com>,
Florian Weimer <fweimer@redhat.com>,
Szabolcs Nagy <nsz@port70.net>, Rich Felker <dalias@libc.org>,
libc-alpha@sourceware.org, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org,
Mark Brown <broonie@kernel.org>
Subject: [PATCH RFC 1/3] arm64/gcs: Support reuse of GCS for exited threads
Date: Sun, 21 Sep 2025 14:21:35 +0100 [thread overview]
Message-ID: <20250921-arm64-gcs-exit-token-v1-1-45cf64e648d5@kernel.org> (raw)
In-Reply-To: <20250921-arm64-gcs-exit-token-v1-0-45cf64e648d5@kernel.org>
Currently when a thread with a userspace allocated stack exits it is not
possible for the GCS that was in use by the thread to be reused since no
stack switch token will be left on the stack, preventing use with
clone3() or userspace stack switching. The only thing userspace can
realistically do with the GCS is inspect it or unmap it which is not
ideal.
Enable reuse by modelling thread exit like pivoting in userspace with
the stack pivot instructions, writing a stack switch token at the top
entry of the GCS of the exiting thread. This allows userspace to switch
back to the GCS in future, the use of the current stack location should
work well with glibc's current behaviour of fully uwninding the stack of
threads that exit cleanly.
This patch is an RFC and should not be applied as-is. Currently the
token will only be written for the current thread, but will be written
regardless of the reason the thread is exiting. This version of the
patch does not handle scheduling during exit() at all, the code is racy.
The feature is gated behind a new GCS mode flag PR_SHADOW_STACK_EXIT_TOKEN
to ensure that userspace that does not wish to use the tokens never has
to see them.
Signed-off-by: Mark Brown <broonie@kernel.org>
---
arch/arm64/include/asm/gcs.h | 3 ++-
arch/arm64/mm/gcs.c | 25 ++++++++++++++++++++++++-
include/uapi/linux/prctl.h | 1 +
3 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/include/asm/gcs.h b/arch/arm64/include/asm/gcs.h
index b4bbec9382a1..1ec359d0ad51 100644
--- a/arch/arm64/include/asm/gcs.h
+++ b/arch/arm64/include/asm/gcs.h
@@ -52,7 +52,8 @@ static inline u64 gcsss2(void)
}
#define PR_SHADOW_STACK_SUPPORTED_STATUS_MASK \
- (PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_WRITE | PR_SHADOW_STACK_PUSH)
+ (PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_WRITE | \
+ PR_SHADOW_STACK_PUSH | PR_SHADOW_STACK_EXIT_TOKEN)
#ifdef CONFIG_ARM64_GCS
diff --git a/arch/arm64/mm/gcs.c b/arch/arm64/mm/gcs.c
index fd1d5a6655de..4649c2b107a7 100644
--- a/arch/arm64/mm/gcs.c
+++ b/arch/arm64/mm/gcs.c
@@ -199,14 +199,37 @@ void gcs_set_el0_mode(struct task_struct *task)
void gcs_free(struct task_struct *task)
{
+ unsigned long __user *cap_ptr;
+ unsigned long cap_val;
+ int ret;
+
if (!system_supports_gcs())
return;
if (!task->mm || task->mm != current->mm)
return;
- if (task->thread.gcs_base)
+ if (task->thread.gcs_base) {
vm_munmap(task->thread.gcs_base, task->thread.gcs_size);
+ } else if (task == current &&
+ task->thread.gcs_el0_mode & PR_SHADOW_STACK_EXIT_TOKEN) {
+ cap_ptr = (unsigned long __user *)read_sysreg_s(SYS_GCSPR_EL0);
+ cap_ptr--;
+ cap_val = GCS_CAP(cap_ptr);
+
+ /*
+ * We can't do anything constructive if this fails,
+ * and the thread might be exiting due to being in a
+ * bad state anyway.
+ */
+ put_user_gcs(cap_val, cap_ptr, &ret);
+
+ /*
+ * Ensure the new cap is ordered before standard
+ * memory accesses to the same location.
+ */
+ gcsb_dsync();
+ }
task->thread.gcspr_el0 = 0;
task->thread.gcs_base = 0;
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index ed3aed264aeb..c3c37c39639f 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -352,6 +352,7 @@ struct prctl_mm_map {
# define PR_SHADOW_STACK_ENABLE (1UL << 0)
# define PR_SHADOW_STACK_WRITE (1UL << 1)
# define PR_SHADOW_STACK_PUSH (1UL << 2)
+# define PR_SHADOW_STACK_EXIT_TOKEN (1UL << 3)
/*
* Prevent further changes to the specified shadow stack
--
2.47.2
next prev parent reply other threads:[~2025-09-21 13:25 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-21 13:21 [PATCH RFC 0/3] arm64/gcs: Allow reuse of user managed shadow stacks Mark Brown
2025-09-21 13:21 ` Mark Brown [this message]
2025-09-25 16:46 ` [PATCH RFC 1/3] arm64/gcs: Support reuse of GCS for exited threads Catalin Marinas
2025-09-25 17:01 ` Mark Brown
2025-09-25 18:36 ` Catalin Marinas
2025-09-25 19:00 ` Mark Brown
2025-09-26 11:14 ` Catalin Marinas
2025-09-26 11:37 ` Mark Brown
2025-09-21 13:21 ` [PATCH RFC 2/3] kselftest/arm64: Validate PR_SHADOW_STACK_EXIT_TOKEN in basic-gcs Mark Brown
2025-09-21 13:21 ` [PATCH RFC 3/3] kselftest/arm64: Add PR_SHADOW_STACK_EXIT_TOKEN to gcs-locking Mark Brown
2025-09-25 20:40 ` [PATCH RFC 0/3] arm64/gcs: Allow reuse of user managed shadow stacks Edgecombe, Rick P
2025-09-25 23:22 ` Mark Brown
2025-09-25 23:58 ` Edgecombe, Rick P
2025-09-26 0:44 ` Mark Brown
2025-09-26 15:46 ` Edgecombe, Rick P
2025-09-26 16:09 ` Mark Brown
2025-09-29 18:37 ` Deepak Gupta
2025-09-26 15:07 ` Yury Khrustalev
2025-09-26 15:39 ` Edgecombe, Rick P
2025-09-26 16:03 ` Mark Brown
2025-09-26 19:17 ` Edgecombe, Rick P
2025-09-29 15:47 ` Mark Brown
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=20250921-arm64-gcs-exit-token-v1-1-45cf64e648d5@kernel.org \
--to=broonie@kernel.org \
--cc=adhemerval.zanella@linaro.org \
--cc=brauner@kernel.org \
--cc=catalin.marinas@arm.com \
--cc=codonell@redhat.com \
--cc=dalias@libc.org \
--cc=debug@rivosinc.com \
--cc=fweimer@redhat.com \
--cc=libc-alpha@sourceware.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=nsz@port70.net \
--cc=rick.p.edgecombe@intel.com \
--cc=shuah@kernel.org \
--cc=wilco.dijkstra@arm.com \
--cc=will@kernel.org \
/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®