* [PATCH v5 0/7] arm64: Enable UPROBES with GCS
@ 2025-08-11 14:10 Jeremy Linton
2025-08-11 14:10 ` [PATCH v5 1/7] arm64: probes: Break ret out from bl/blr Jeremy Linton
` (6 more replies)
0 siblings, 7 replies; 13+ messages in thread
From: Jeremy Linton @ 2025-08-11 14:10 UTC (permalink / raw)
To: linux-trace-kernel
Cc: linux-perf-users, mhiramat, oleg, peterz, mingo, acme, namhyung,
mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter,
kan.liang, thiago.bauermann, broonie, yury.khrustalev,
kristina.martsenko, liaochang1, catalin.marinas, will,
linux-arm-kernel, linux-kernel, Jeremy Linton
Currently uprobes and the Arm Guarded Control Stack (GCS) feature are
exclusive of each other. This restriction needs to be lifted in order
to utilize GCS for generic Linux distro images where the expectation
is that core debugging features like uprobes work.
This series adds some user accessors to read/push/pop the userspace
shadow stack. It then utilizes those functions in the uprobe paths as
needed to synchronize GCS with the changes in control flow at probe
locations.
The KCONFIG restriction is then dropped.
v4->v5: Fix ret xn handing
Renames, comment tweaks, formatting, per review comments
rebase 6.17, drop first patch
Add reviewed-by's
v3->v4: Much delayed v4 rebased to 6.16
Move existing gcs accessors to gcs.h and then add the new
ones. This fixes some of the forward reference issues,
the build break and keeps them all together.
v2->v3: Cleanup RET logic to alwaays use LR, and not update IP on aborts
Correct generic uprobe_warn bug even though we aren't using it
v1->v2:
Drop uprobe_warn() patch
Fix copy_thread_gcs() bug created by fixing task_gcs_el0_enabled()
Comments, now describe issues with reading userspace GCS pages
Rebased to 6.15
Jeremy Linton (7):
arm64: probes: Break ret out from bl/blr
arm64: uaccess: Move existing GCS accessors definitions to gcs.h
arm64: uaccess: Add additional userspace GCS accessors
arm64: probes: Add GCS support to bl/blr/ret
arm64: uprobes: Add GCS support to uretprobes
arm64: Kconfig: Remove GCS restrictions on UPROBES
uprobes: uprobe_warn should use passed task
arch/arm64/Kconfig | 1 -
arch/arm64/include/asm/gcs.h | 89 ++++++++++++++++++++++++
arch/arm64/include/asm/uaccess.h | 40 -----------
arch/arm64/kernel/probes/decode-insn.c | 7 +-
arch/arm64/kernel/probes/simulate-insn.c | 50 ++++++++++---
arch/arm64/kernel/probes/simulate-insn.h | 3 +-
arch/arm64/kernel/probes/uprobes.c | 33 +++++++++
kernel/events/uprobes.c | 2 +-
8 files changed, 171 insertions(+), 54 deletions(-)
--
2.50.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v5 1/7] arm64: probes: Break ret out from bl/blr
2025-08-11 14:10 [PATCH v5 0/7] arm64: Enable UPROBES with GCS Jeremy Linton
@ 2025-08-11 14:10 ` Jeremy Linton
2025-08-11 14:10 ` [PATCH v5 2/7] arm64: uaccess: Move existing GCS accessors definitions to gcs.h Jeremy Linton
` (5 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: Jeremy Linton @ 2025-08-11 14:10 UTC (permalink / raw)
To: linux-trace-kernel
Cc: linux-perf-users, mhiramat, oleg, peterz, mingo, acme, namhyung,
mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter,
kan.liang, thiago.bauermann, broonie, yury.khrustalev,
kristina.martsenko, liaochang1, catalin.marinas, will,
linux-arm-kernel, linux-kernel, Jeremy Linton
Prepare for GCS by breaking RET out into its own function, where
it makes more sense to encapsulate the new behavior independent
from the branch instructions.
Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm64/kernel/probes/decode-insn.c | 7 ++++---
arch/arm64/kernel/probes/simulate-insn.c | 10 +++++++++-
arch/arm64/kernel/probes/simulate-insn.h | 3 ++-
3 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/kernel/probes/decode-insn.c b/arch/arm64/kernel/probes/decode-insn.c
index 6438bf62e753..4137cc5ef031 100644
--- a/arch/arm64/kernel/probes/decode-insn.c
+++ b/arch/arm64/kernel/probes/decode-insn.c
@@ -108,9 +108,10 @@ arm_probe_decode_insn(u32 insn, struct arch_probe_insn *api)
aarch64_insn_is_bl(insn)) {
api->handler = simulate_b_bl;
} else if (aarch64_insn_is_br(insn) ||
- aarch64_insn_is_blr(insn) ||
- aarch64_insn_is_ret(insn)) {
- api->handler = simulate_br_blr_ret;
+ aarch64_insn_is_blr(insn)) {
+ api->handler = simulate_br_blr;
+ } else if (aarch64_insn_is_ret(insn)) {
+ api->handler = simulate_ret;
} else {
/*
* Instruction cannot be stepped out-of-line and we don't
diff --git a/arch/arm64/kernel/probes/simulate-insn.c b/arch/arm64/kernel/probes/simulate-insn.c
index 4c6d2d712fbd..09a0b36122d0 100644
--- a/arch/arm64/kernel/probes/simulate-insn.c
+++ b/arch/arm64/kernel/probes/simulate-insn.c
@@ -126,7 +126,7 @@ simulate_b_cond(u32 opcode, long addr, struct pt_regs *regs)
}
void __kprobes
-simulate_br_blr_ret(u32 opcode, long addr, struct pt_regs *regs)
+simulate_br_blr(u32 opcode, long addr, struct pt_regs *regs)
{
int xn = (opcode >> 5) & 0x1f;
@@ -138,6 +138,14 @@ simulate_br_blr_ret(u32 opcode, long addr, struct pt_regs *regs)
set_x_reg(regs, 30, addr + 4);
}
+void __kprobes
+simulate_ret(u32 opcode, long addr, struct pt_regs *regs)
+{
+ int xn = (opcode >> 5) & 0x1f;
+
+ instruction_pointer_set(regs, get_x_reg(regs, xn));
+}
+
void __kprobes
simulate_cbz_cbnz(u32 opcode, long addr, struct pt_regs *regs)
{
diff --git a/arch/arm64/kernel/probes/simulate-insn.h b/arch/arm64/kernel/probes/simulate-insn.h
index efb2803ec943..9e772a292d56 100644
--- a/arch/arm64/kernel/probes/simulate-insn.h
+++ b/arch/arm64/kernel/probes/simulate-insn.h
@@ -11,7 +11,8 @@
void simulate_adr_adrp(u32 opcode, long addr, struct pt_regs *regs);
void simulate_b_bl(u32 opcode, long addr, struct pt_regs *regs);
void simulate_b_cond(u32 opcode, long addr, struct pt_regs *regs);
-void simulate_br_blr_ret(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_br_blr(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_ret(u32 opcode, long addr, struct pt_regs *regs);
void simulate_cbz_cbnz(u32 opcode, long addr, struct pt_regs *regs);
void simulate_tbz_tbnz(u32 opcode, long addr, struct pt_regs *regs);
void simulate_ldr_literal(u32 opcode, long addr, struct pt_regs *regs);
--
2.50.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 2/7] arm64: uaccess: Move existing GCS accessors definitions to gcs.h
2025-08-11 14:10 [PATCH v5 0/7] arm64: Enable UPROBES with GCS Jeremy Linton
2025-08-11 14:10 ` [PATCH v5 1/7] arm64: probes: Break ret out from bl/blr Jeremy Linton
@ 2025-08-11 14:10 ` Jeremy Linton
2025-08-11 14:10 ` [PATCH v5 3/7] arm64: uaccess: Add additional userspace GCS accessors Jeremy Linton
` (4 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: Jeremy Linton @ 2025-08-11 14:10 UTC (permalink / raw)
To: linux-trace-kernel
Cc: linux-perf-users, mhiramat, oleg, peterz, mingo, acme, namhyung,
mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter,
kan.liang, thiago.bauermann, broonie, yury.khrustalev,
kristina.martsenko, liaochang1, catalin.marinas, will,
linux-arm-kernel, linux-kernel, Jeremy Linton
We are going to add some additional GCS access helpers to gcs.h in
order to avoid some forward reference problems with uaccess.
In preparation for that, lets move the existing gcssttr() and
put_user_gcs() routines into gcs.h where it makes sense to keep all
the accessors together. Further, the code which uses them already
includes gcs.h and there is an existing CONFIG_ARM64_GCS check we can
reuse.
Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm64/include/asm/gcs.h | 35 ++++++++++++++++++++++++++++
arch/arm64/include/asm/uaccess.h | 40 --------------------------------
2 files changed, 35 insertions(+), 40 deletions(-)
diff --git a/arch/arm64/include/asm/gcs.h b/arch/arm64/include/asm/gcs.h
index 5bc432234d3a..e3b360c9dba4 100644
--- a/arch/arm64/include/asm/gcs.h
+++ b/arch/arm64/include/asm/gcs.h
@@ -81,6 +81,41 @@ static inline int gcs_check_locked(struct task_struct *task,
return 0;
}
+static inline int gcssttr(unsigned long __user *addr, unsigned long val)
+{
+ register unsigned long __user *_addr __asm__ ("x0") = addr;
+ register unsigned long _val __asm__ ("x1") = val;
+ int err = 0;
+
+ /* GCSSTTR x1, x0 */
+ asm volatile(
+ "1: .inst 0xd91f1c01\n"
+ "2: \n"
+ _ASM_EXTABLE_UACCESS_ERR(1b, 2b, %w0)
+ : "+r" (err)
+ : "rZ" (_val), "r" (_addr)
+ : "memory");
+
+ return err;
+}
+
+static inline void put_user_gcs(unsigned long val, unsigned long __user *addr,
+ int *err)
+{
+ int ret;
+
+ if (!access_ok((char __user *)addr, sizeof(u64))) {
+ *err = -EFAULT;
+ return;
+ }
+
+ uaccess_ttbr0_enable();
+ ret = gcssttr(addr, val);
+ if (ret != 0)
+ *err = ret;
+ uaccess_ttbr0_disable();
+}
+
#else
static inline bool task_gcs_el0_enabled(struct task_struct *task)
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 5b91803201ef..1aa4ecb73429 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -502,44 +502,4 @@ static inline size_t probe_subpage_writeable(const char __user *uaddr,
#endif /* CONFIG_ARCH_HAS_SUBPAGE_FAULTS */
-#ifdef CONFIG_ARM64_GCS
-
-static inline int gcssttr(unsigned long __user *addr, unsigned long val)
-{
- register unsigned long __user *_addr __asm__ ("x0") = addr;
- register unsigned long _val __asm__ ("x1") = val;
- int err = 0;
-
- /* GCSSTTR x1, x0 */
- asm volatile(
- "1: .inst 0xd91f1c01\n"
- "2: \n"
- _ASM_EXTABLE_UACCESS_ERR(1b, 2b, %w0)
- : "+r" (err)
- : "rZ" (_val), "r" (_addr)
- : "memory");
-
- return err;
-}
-
-static inline void put_user_gcs(unsigned long val, unsigned long __user *addr,
- int *err)
-{
- int ret;
-
- if (!access_ok((char __user *)addr, sizeof(u64))) {
- *err = -EFAULT;
- return;
- }
-
- uaccess_ttbr0_enable();
- ret = gcssttr(addr, val);
- if (ret != 0)
- *err = ret;
- uaccess_ttbr0_disable();
-}
-
-
-#endif /* CONFIG_ARM64_GCS */
-
#endif /* __ASM_UACCESS_H */
--
2.50.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 3/7] arm64: uaccess: Add additional userspace GCS accessors
2025-08-11 14:10 [PATCH v5 0/7] arm64: Enable UPROBES with GCS Jeremy Linton
2025-08-11 14:10 ` [PATCH v5 1/7] arm64: probes: Break ret out from bl/blr Jeremy Linton
2025-08-11 14:10 ` [PATCH v5 2/7] arm64: uaccess: Move existing GCS accessors definitions to gcs.h Jeremy Linton
@ 2025-08-11 14:10 ` Jeremy Linton
2025-08-11 14:40 ` Jeremy Linton
2025-08-11 14:10 ` [PATCH v5 4/7] arm64: probes: Add GCS support to bl/blr/ret Jeremy Linton
` (3 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Jeremy Linton @ 2025-08-11 14:10 UTC (permalink / raw)
To: linux-trace-kernel
Cc: linux-perf-users, mhiramat, oleg, peterz, mingo, acme, namhyung,
mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter,
kan.liang, thiago.bauermann, broonie, yury.khrustalev,
kristina.martsenko, liaochang1, catalin.marinas, will,
linux-arm-kernel, linux-kernel, Jeremy Linton
Uprobes need more advanced read, push, and pop userspace GCS
functionality. Implement those features using the existing gcsstr()
and copy_from_user().
Its important to note that GCS pages can be read by normal
instructions, but the hardware validates that pages used by GCS
specific operations, have a GCS privilege set. We aren't validating this
in load_user_gcs because it requires stabilizing the VMA over the read
which may fault.
Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm64/include/asm/gcs.h | 54 ++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/arch/arm64/include/asm/gcs.h b/arch/arm64/include/asm/gcs.h
index e3b360c9dba4..bd9ff1dedcd9 100644
--- a/arch/arm64/include/asm/gcs.h
+++ b/arch/arm64/include/asm/gcs.h
@@ -116,6 +116,47 @@ static inline void put_user_gcs(unsigned long val, unsigned long __user *addr,
uaccess_ttbr0_disable();
}
+static inline void push_user_gcs(unsigned long val, int *err)
+{
+ u64 gcspr = read_sysreg_s(SYS_GCSPR_EL0);
+
+ gcspr -= sizeof(u64);
+ put_user_gcs(val, (unsigned long __user *)gcspr, err);
+ if (!*err)
+ write_sysreg_s(gcspr, SYS_GCSPR_EL0);
+}
+
+/*
+ * Unlike put/push_user_gcs() above, get/pop_user_gsc() doesn't
+ * validate the GCS permission is set on the page being read. This
+ * differs from how the hardware works when it consumes data stored at
+ * GCSPR. Callers should assure this is acceptable.
+ */
+static inline u64 get_user_gcs(unsigned long __user *addr, int *err)
+{
+ unsigned long ret;
+ u64 load = 0;
+
+ /* Ensure previous GCS operation are visible before we read the page */
+ gcsb_dsync();
+ ret = copy_from_user(&load, addr, sizeof(load));
+ if (ret != 0)
+ *err = ret;
+ return load;
+}
+
+static inline u64 pop_user_gcs(int *err)
+{
+ u64 gcspr = read_sysreg_s(SYS_GCSPR_EL0);
+ u64 read_val;
+
+ read_val = get_user_gcs((unsigned long __user *)gcspr, err);
+ if (!*err)
+ write_sysreg_s(gcspr + sizeof(u64), SYS_GCSPR_EL0);
+
+ return read_val;
+}
+
#else
static inline bool task_gcs_el0_enabled(struct task_struct *task)
@@ -126,6 +167,10 @@ 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 put_user_gcs(unsigned long val, unsigned long __user *addr,
+ int *err) { }
+static inline void push_user_gcs(unsigned long val, int *err) { }
+
static inline unsigned long gcs_alloc_thread_stack(struct task_struct *tsk,
const struct kernel_clone_args *args)
{
@@ -136,6 +181,15 @@ static inline int gcs_check_locked(struct task_struct *task,
{
return 0;
}
+static inline u64 load_user_gcs(unsigned long __user *addr, int *err)
+{
+ *err = -EFAULT;
+ return 0;
+}
+static inline u64 pop_user_gcs(int *err)
+{
+ return 0;
+}
#endif
--
2.50.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 4/7] arm64: probes: Add GCS support to bl/blr/ret
2025-08-11 14:10 [PATCH v5 0/7] arm64: Enable UPROBES with GCS Jeremy Linton
` (2 preceding siblings ...)
2025-08-11 14:10 ` [PATCH v5 3/7] arm64: uaccess: Add additional userspace GCS accessors Jeremy Linton
@ 2025-08-11 14:10 ` Jeremy Linton
2025-08-15 14:08 ` Catalin Marinas
2025-08-11 14:10 ` [PATCH v5 5/7] arm64: uprobes: Add GCS support to uretprobes Jeremy Linton
` (2 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Jeremy Linton @ 2025-08-11 14:10 UTC (permalink / raw)
To: linux-trace-kernel
Cc: linux-perf-users, mhiramat, oleg, peterz, mingo, acme, namhyung,
mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter,
kan.liang, thiago.bauermann, broonie, yury.khrustalev,
kristina.martsenko, liaochang1, catalin.marinas, will,
linux-arm-kernel, linux-kernel, Jeremy Linton
The arm64 probe simulation doesn't currently have logic in place
to deal with GCS and this results in core dumps if probes are inserted
at control flow locations. Fix-up bl, blr and ret to manipulate the
shadow stack as needed.
While we manipulate and validate the shadow stack correctly, the
hardware provides additional security by only allowing GCS operations
against pages which are marked to support GCS. For writing there is
gcssttr() which enforces this, but there isn't an equivalent for
reading. This means that uprobe users should be aware that probing on
control flow instructions which require reading the shadow stack (ex:
ret) offers lower security guarantees than what is achieved without
the uprobe active.
Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
arch/arm64/kernel/probes/simulate-insn.c | 44 +++++++++++++++++++-----
1 file changed, 35 insertions(+), 9 deletions(-)
diff --git a/arch/arm64/kernel/probes/simulate-insn.c b/arch/arm64/kernel/probes/simulate-insn.c
index 09a0b36122d0..97ed4db75417 100644
--- a/arch/arm64/kernel/probes/simulate-insn.c
+++ b/arch/arm64/kernel/probes/simulate-insn.c
@@ -13,6 +13,7 @@
#include <asm/traps.h>
#include "simulate-insn.h"
+#include "asm/gcs.h"
#define bbl_displacement(insn) \
sign_extend32(((insn) & 0x3ffffff) << 2, 27)
@@ -49,6 +50,21 @@ static inline u32 get_w_reg(struct pt_regs *regs, int reg)
return lower_32_bits(pt_regs_read_reg(regs, reg));
}
+static inline int update_lr(struct pt_regs *regs, long addr)
+{
+ int err = 0;
+
+ if (user_mode(regs) && task_gcs_el0_enabled(current)) {
+ push_user_gcs(addr, &err);
+ if (err) {
+ force_sig(SIGSEGV);
+ return err;
+ }
+ }
+ procedure_link_pointer_set(regs, addr);
+ return err;
+}
+
static bool __kprobes check_cbz(u32 opcode, struct pt_regs *regs)
{
int xn = opcode & 0x1f;
@@ -107,9 +123,9 @@ simulate_b_bl(u32 opcode, long addr, struct pt_regs *regs)
{
int disp = bbl_displacement(opcode);
- /* Link register is x30 */
if (opcode & (1 << 31))
- set_x_reg(regs, 30, addr + 4);
+ if (update_lr(regs, addr + 4))
+ return;
instruction_pointer_set(regs, addr + disp);
}
@@ -129,21 +145,31 @@ void __kprobes
simulate_br_blr(u32 opcode, long addr, struct pt_regs *regs)
{
int xn = (opcode >> 5) & 0x1f;
+ int b_target = get_x_reg(regs, xn);
- /* update pc first in case we're doing a "blr lr" */
- instruction_pointer_set(regs, get_x_reg(regs, xn));
-
- /* Link register is x30 */
if (((opcode >> 21) & 0x3) == 1)
- set_x_reg(regs, 30, addr + 4);
+ if (update_lr(regs, addr + 4))
+ return;
+
+ instruction_pointer_set(regs, b_target);
}
void __kprobes
simulate_ret(u32 opcode, long addr, struct pt_regs *regs)
{
+ u64 ret_addr;
+ int err = 0;
int xn = (opcode >> 5) & 0x1f;
-
- instruction_pointer_set(regs, get_x_reg(regs, xn));
+ unsigned long r_target = get_x_reg(regs, xn);
+
+ if (user_mode(regs) && task_gcs_el0_enabled(current)) {
+ ret_addr = pop_user_gcs(&err);
+ if (err || ret_addr != r_target) {
+ force_sig(SIGSEGV);
+ return;
+ }
+ }
+ instruction_pointer_set(regs, r_target);
}
void __kprobes
--
2.50.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 5/7] arm64: uprobes: Add GCS support to uretprobes
2025-08-11 14:10 [PATCH v5 0/7] arm64: Enable UPROBES with GCS Jeremy Linton
` (3 preceding siblings ...)
2025-08-11 14:10 ` [PATCH v5 4/7] arm64: probes: Add GCS support to bl/blr/ret Jeremy Linton
@ 2025-08-11 14:10 ` Jeremy Linton
2025-08-13 6:12 ` kernel test robot
2025-08-11 14:10 ` [PATCH v5 6/7] arm64: Kconfig: Remove GCS restrictions on UPROBES Jeremy Linton
2025-08-11 14:10 ` [PATCH v5 7/7] uprobes: uprobe_warn should use passed task Jeremy Linton
6 siblings, 1 reply; 13+ messages in thread
From: Jeremy Linton @ 2025-08-11 14:10 UTC (permalink / raw)
To: linux-trace-kernel
Cc: linux-perf-users, mhiramat, oleg, peterz, mingo, acme, namhyung,
mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter,
kan.liang, thiago.bauermann, broonie, yury.khrustalev,
kristina.martsenko, liaochang1, catalin.marinas, will,
linux-arm-kernel, linux-kernel, Jeremy Linton, Steve Capper
Ret probes work by changing the value in the link register at
the probe location to return to the probe rather than the calling
routine. Thus the GCS needs to be updated with this address as well.
Since its possible to insert probes at locations where the
current value of the LR doesn't match the GCS state this needs
to be detected and handled in order to maintain the existing
no-fault behavior.
Co-developed-by: Steve Capper <steve.capper@arm.com>
Signed-off-by: Steve Capper <steve.capper@arm.com>
(updated to use new gcs accessors, and handle LR/GCS mismatches)
Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm64/kernel/probes/uprobes.c | 33 ++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/arch/arm64/kernel/probes/uprobes.c b/arch/arm64/kernel/probes/uprobes.c
index 1f91fd2a8187..6b98503a0198 100644
--- a/arch/arm64/kernel/probes/uprobes.c
+++ b/arch/arm64/kernel/probes/uprobes.c
@@ -6,6 +6,7 @@
#include <linux/ptrace.h>
#include <linux/uprobes.h>
#include <asm/cacheflush.h>
+#include <asm/gcs.h>
#include "decode-insn.h"
@@ -159,11 +160,43 @@ arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
struct pt_regs *regs)
{
unsigned long orig_ret_vaddr;
+ unsigned long gcs_ret_vaddr;
+ int err = 0;
+ u64 gcspr;
orig_ret_vaddr = procedure_link_pointer(regs);
+
+ if (task_gcs_el0_enabled(current)) {
+ gcspr = read_sysreg_s(SYS_GCSPR_EL0);
+ gcs_ret_vaddr = get_user_gcs((unsigned long __user *)gcspr, &err);
+ if (err) {
+ force_sig(SIGSEGV);
+ goto out;
+ }
+
+ /*
+ * If the LR and GCS return addr don't match, then some kind of PAC
+ * signing or control flow occurred since entering the probed function.
+ * Likely because the user is attempting to retprobe on an instruction
+ * that isn't a function boundary or inside a leaf function. Explicitly
+ * abort this retprobe because it will generate a GCS exception.
+ */
+ if (gcs_ret_vaddr != orig_ret_vaddr) {
+ orig_ret_vaddr = -1;
+ goto out;
+ }
+
+ put_user_gcs(trampoline_vaddr, (unsigned long __user *)gcspr, &err);
+ if (err) {
+ force_sig(SIGSEGV);
+ goto out;
+ }
+ }
+
/* Replace the return addr with trampoline addr */
procedure_link_pointer_set(regs, trampoline_vaddr);
+out:
return orig_ret_vaddr;
}
--
2.50.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 6/7] arm64: Kconfig: Remove GCS restrictions on UPROBES
2025-08-11 14:10 [PATCH v5 0/7] arm64: Enable UPROBES with GCS Jeremy Linton
` (4 preceding siblings ...)
2025-08-11 14:10 ` [PATCH v5 5/7] arm64: uprobes: Add GCS support to uretprobes Jeremy Linton
@ 2025-08-11 14:10 ` Jeremy Linton
2025-08-11 14:10 ` [PATCH v5 7/7] uprobes: uprobe_warn should use passed task Jeremy Linton
6 siblings, 0 replies; 13+ messages in thread
From: Jeremy Linton @ 2025-08-11 14:10 UTC (permalink / raw)
To: linux-trace-kernel
Cc: linux-perf-users, mhiramat, oleg, peterz, mingo, acme, namhyung,
mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter,
kan.liang, thiago.bauermann, broonie, yury.khrustalev,
kristina.martsenko, liaochang1, catalin.marinas, will,
linux-arm-kernel, linux-kernel, Jeremy Linton
Now that the uprobe paths have been made GCS compatible
drop the Kconfig restriction.
Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm64/Kconfig | 1 -
1 file changed, 1 deletion(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index e9bbfacc35a6..c61572bbe59b 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2225,7 +2225,6 @@ config ARM64_GCS
default y
select ARCH_HAS_USER_SHADOW_STACK
select ARCH_USES_HIGH_VMA_FLAGS
- depends on !UPROBES
help
Guarded Control Stack (GCS) provides support for a separate
stack with restricted access which contains only return
--
2.50.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v5 7/7] uprobes: uprobe_warn should use passed task
2025-08-11 14:10 [PATCH v5 0/7] arm64: Enable UPROBES with GCS Jeremy Linton
` (5 preceding siblings ...)
2025-08-11 14:10 ` [PATCH v5 6/7] arm64: Kconfig: Remove GCS restrictions on UPROBES Jeremy Linton
@ 2025-08-11 14:10 ` Jeremy Linton
2025-08-15 14:09 ` Catalin Marinas
6 siblings, 1 reply; 13+ messages in thread
From: Jeremy Linton @ 2025-08-11 14:10 UTC (permalink / raw)
To: linux-trace-kernel
Cc: linux-perf-users, mhiramat, oleg, peterz, mingo, acme, namhyung,
mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter,
kan.liang, thiago.bauermann, broonie, yury.khrustalev,
kristina.martsenko, liaochang1, catalin.marinas, will,
linux-arm-kernel, linux-kernel, Jeremy Linton
uprobe_warn() is passed a task structure, yet its using current. For
the most part this shouldn't matter, but since a task structure is
provided, lets use it.
Fixes: 248d3a7b2f10 ("uprobes: Change uprobe_copy_process() to dup return_instances")
Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
Acked-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
kernel/events/uprobes.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 7ca1940607bd..4b97d16f731c 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -121,7 +121,7 @@ struct xol_area {
static void uprobe_warn(struct task_struct *t, const char *msg)
{
- pr_warn("uprobe: %s:%d failed to %s\n", current->comm, current->pid, msg);
+ pr_warn("uprobe: %s:%d failed to %s\n", t->comm, t->pid, msg);
}
/*
--
2.50.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v5 3/7] arm64: uaccess: Add additional userspace GCS accessors
2025-08-11 14:10 ` [PATCH v5 3/7] arm64: uaccess: Add additional userspace GCS accessors Jeremy Linton
@ 2025-08-11 14:40 ` Jeremy Linton
0 siblings, 0 replies; 13+ messages in thread
From: Jeremy Linton @ 2025-08-11 14:40 UTC (permalink / raw)
To: linux-trace-kernel
Cc: linux-perf-users, mhiramat, oleg, peterz, mingo, acme, namhyung,
mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter,
kan.liang, thiago.bauermann, broonie, yury.khrustalev,
kristina.martsenko, liaochang1, catalin.marinas, will,
linux-arm-kernel, linux-kernel
On 8/11/25 9:10 AM, Jeremy Linton wrote:
> Uprobes need more advanced read, push, and pop userspace GCS
> functionality. Implement those features using the existing gcsstr()
> and copy_from_user().
>
> Its important to note that GCS pages can be read by normal
> instructions, but the hardware validates that pages used by GCS
> specific operations, have a GCS privilege set. We aren't validating this
> in load_user_gcs because it requires stabilizing the VMA over the read
> which may fault.
>
> Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
> ---
> arch/arm64/include/asm/gcs.h | 54 ++++++++++++++++++++++++++++++++++++
> 1 file changed, 54 insertions(+)
>
> diff --git a/arch/arm64/include/asm/gcs.h b/arch/arm64/include/asm/gcs.h
> index e3b360c9dba4..bd9ff1dedcd9 100644
> --- a/arch/arm64/include/asm/gcs.h
> +++ b/arch/arm64/include/asm/gcs.h
> @@ -116,6 +116,47 @@ static inline void put_user_gcs(unsigned long val, unsigned long __user *addr,
> uaccess_ttbr0_disable();
> }
>
> +static inline void push_user_gcs(unsigned long val, int *err)
> +{
> + u64 gcspr = read_sysreg_s(SYS_GCSPR_EL0);
> +
> + gcspr -= sizeof(u64);
> + put_user_gcs(val, (unsigned long __user *)gcspr, err);
> + if (!*err)
> + write_sysreg_s(gcspr, SYS_GCSPR_EL0);
> +}
> +
> +/*
> + * Unlike put/push_user_gcs() above, get/pop_user_gsc() doesn't
> + * validate the GCS permission is set on the page being read. This
> + * differs from how the hardware works when it consumes data stored at
> + * GCSPR. Callers should assure this is acceptable.
> + */
> +static inline u64 get_user_gcs(unsigned long __user *addr, int *err)
> +{
> + unsigned long ret;
> + u64 load = 0;
> +
> + /* Ensure previous GCS operation are visible before we read the page */
> + gcsb_dsync();
> + ret = copy_from_user(&load, addr, sizeof(load));
> + if (ret != 0)
> + *err = ret;
> + return load;
> +}
> +
> +static inline u64 pop_user_gcs(int *err)
> +{
> + u64 gcspr = read_sysreg_s(SYS_GCSPR_EL0);
> + u64 read_val;
> +
> + read_val = get_user_gcs((unsigned long __user *)gcspr, err);
> + if (!*err)
> + write_sysreg_s(gcspr + sizeof(u64), SYS_GCSPR_EL0);
> +
> + return read_val;
> +}
> +
> #else
>
> static inline bool task_gcs_el0_enabled(struct task_struct *task)
> @@ -126,6 +167,10 @@ 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 put_user_gcs(unsigned long val, unsigned long __user *addr,
> + int *err) { }
> +static inline void push_user_gcs(unsigned long val, int *err) { }
> +
> static inline unsigned long gcs_alloc_thread_stack(struct task_struct *tsk,
> const struct kernel_clone_args *args)
> {
> @@ -136,6 +181,15 @@ static inline int gcs_check_locked(struct task_struct *task,
> {
> return 0;
> }
> +static inline u64 load_user_gcs(unsigned long __user *addr, int *err)
> +{
> + *err = -EFAULT;
> + return 0;
> +}
I sent an old version sine this was sitting around during the merge
window. This should have been renamed along with the version above to
'get_user_gcs'.
> +static inline u64 pop_user_gcs(int *err)
> +{
> + return 0;
> +}
>
> #endif
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v5 5/7] arm64: uprobes: Add GCS support to uretprobes
2025-08-11 14:10 ` [PATCH v5 5/7] arm64: uprobes: Add GCS support to uretprobes Jeremy Linton
@ 2025-08-13 6:12 ` kernel test robot
2025-08-15 14:10 ` Catalin Marinas
0 siblings, 1 reply; 13+ messages in thread
From: kernel test robot @ 2025-08-13 6:12 UTC (permalink / raw)
To: Jeremy Linton, linux-trace-kernel
Cc: oe-kbuild-all, linux-perf-users, mhiramat, oleg, peterz, mingo,
acme, namhyung, mark.rutland, alexander.shishkin, jolsa, irogers,
adrian.hunter, kan.liang, thiago.bauermann, broonie,
yury.khrustalev, kristina.martsenko, liaochang1, catalin.marinas,
will, linux-arm-kernel, linux-kernel, Jeremy Linton, Steve Capper
Hi Jeremy,
kernel test robot noticed the following build errors:
[auto build test ERROR on arm64/for-next/core]
[also build test ERROR on perf-tools-next/perf-tools-next tip/perf/core perf-tools/perf-tools linus/master v6.17-rc1 next-20250812]
[cannot apply to acme/perf/core]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Jeremy-Linton/arm64-probes-Break-ret-out-from-bl-blr/20250811-221529
base: https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/core
patch link: https://lore.kernel.org/r/20250811141010.741989-6-jeremy.linton%40arm.com
patch subject: [PATCH v5 5/7] arm64: uprobes: Add GCS support to uretprobes
config: arm64-randconfig-r111-20250813 (https://download.01.org/0day-ci/archive/20250813/202508131334.FfoZQ27h-lkp@intel.com/config)
compiler: aarch64-linux-gcc (GCC) 13.4.0
reproduce: (https://download.01.org/0day-ci/archive/20250813/202508131334.FfoZQ27h-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202508131334.FfoZQ27h-lkp@intel.com/
All errors (new ones prefixed by >>):
arch/arm64/kernel/probes/uprobes.c: In function 'arch_uretprobe_hijack_return_addr':
>> arch/arm64/kernel/probes/uprobes.c:171:33: error: implicit declaration of function 'get_user_gcs'; did you mean 'put_user_gcs'? [-Werror=implicit-function-declaration]
171 | gcs_ret_vaddr = get_user_gcs((unsigned long __user *)gcspr, &err);
| ^~~~~~~~~~~~
| put_user_gcs
cc1: some warnings being treated as errors
vim +171 arch/arm64/kernel/probes/uprobes.c
157
158 unsigned long
159 arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
160 struct pt_regs *regs)
161 {
162 unsigned long orig_ret_vaddr;
163 unsigned long gcs_ret_vaddr;
164 int err = 0;
165 u64 gcspr;
166
167 orig_ret_vaddr = procedure_link_pointer(regs);
168
169 if (task_gcs_el0_enabled(current)) {
170 gcspr = read_sysreg_s(SYS_GCSPR_EL0);
> 171 gcs_ret_vaddr = get_user_gcs((unsigned long __user *)gcspr, &err);
172 if (err) {
173 force_sig(SIGSEGV);
174 goto out;
175 }
176
177 /*
178 * If the LR and GCS return addr don't match, then some kind of PAC
179 * signing or control flow occurred since entering the probed function.
180 * Likely because the user is attempting to retprobe on an instruction
181 * that isn't a function boundary or inside a leaf function. Explicitly
182 * abort this retprobe because it will generate a GCS exception.
183 */
184 if (gcs_ret_vaddr != orig_ret_vaddr) {
185 orig_ret_vaddr = -1;
186 goto out;
187 }
188
189 put_user_gcs(trampoline_vaddr, (unsigned long __user *)gcspr, &err);
190 if (err) {
191 force_sig(SIGSEGV);
192 goto out;
193 }
194 }
195
196 /* Replace the return addr with trampoline addr */
197 procedure_link_pointer_set(regs, trampoline_vaddr);
198
199 out:
200 return orig_ret_vaddr;
201 }
202
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v5 4/7] arm64: probes: Add GCS support to bl/blr/ret
2025-08-11 14:10 ` [PATCH v5 4/7] arm64: probes: Add GCS support to bl/blr/ret Jeremy Linton
@ 2025-08-15 14:08 ` Catalin Marinas
0 siblings, 0 replies; 13+ messages in thread
From: Catalin Marinas @ 2025-08-15 14:08 UTC (permalink / raw)
To: Jeremy Linton
Cc: linux-trace-kernel, linux-perf-users, mhiramat, oleg, peterz,
mingo, acme, namhyung, mark.rutland, alexander.shishkin, jolsa,
irogers, adrian.hunter, kan.liang, thiago.bauermann, broonie,
yury.khrustalev, kristina.martsenko, liaochang1, will,
linux-arm-kernel, linux-kernel
On Mon, Aug 11, 2025 at 09:10:07AM -0500, Jeremy Linton wrote:
> The arm64 probe simulation doesn't currently have logic in place
> to deal with GCS and this results in core dumps if probes are inserted
> at control flow locations. Fix-up bl, blr and ret to manipulate the
> shadow stack as needed.
>
> While we manipulate and validate the shadow stack correctly, the
> hardware provides additional security by only allowing GCS operations
> against pages which are marked to support GCS. For writing there is
> gcssttr() which enforces this, but there isn't an equivalent for
> reading. This means that uprobe users should be aware that probing on
> control flow instructions which require reading the shadow stack (ex:
> ret) offers lower security guarantees than what is achieved without
> the uprobe active.
>
> Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v5 7/7] uprobes: uprobe_warn should use passed task
2025-08-11 14:10 ` [PATCH v5 7/7] uprobes: uprobe_warn should use passed task Jeremy Linton
@ 2025-08-15 14:09 ` Catalin Marinas
0 siblings, 0 replies; 13+ messages in thread
From: Catalin Marinas @ 2025-08-15 14:09 UTC (permalink / raw)
To: Jeremy Linton
Cc: linux-trace-kernel, linux-perf-users, mhiramat, oleg, peterz,
mingo, acme, namhyung, mark.rutland, alexander.shishkin, jolsa,
irogers, adrian.hunter, kan.liang, thiago.bauermann, broonie,
yury.khrustalev, kristina.martsenko, liaochang1, will,
linux-arm-kernel, linux-kernel
On Mon, Aug 11, 2025 at 09:10:10AM -0500, Jeremy Linton wrote:
> uprobe_warn() is passed a task structure, yet its using current. For
> the most part this shouldn't matter, but since a task structure is
> provided, lets use it.
>
> Fixes: 248d3a7b2f10 ("uprobes: Change uprobe_copy_process() to dup return_instances")
> Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
> Acked-by: Oleg Nesterov <oleg@redhat.com>
> Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v5 5/7] arm64: uprobes: Add GCS support to uretprobes
2025-08-13 6:12 ` kernel test robot
@ 2025-08-15 14:10 ` Catalin Marinas
0 siblings, 0 replies; 13+ messages in thread
From: Catalin Marinas @ 2025-08-15 14:10 UTC (permalink / raw)
To: kernel test robot
Cc: Jeremy Linton, linux-trace-kernel, oe-kbuild-all,
linux-perf-users, mhiramat, oleg, peterz, mingo, acme, namhyung,
mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter,
kan.liang, thiago.bauermann, broonie, yury.khrustalev,
kristina.martsenko, liaochang1, will, linux-arm-kernel,
linux-kernel, Steve Capper
On Wed, Aug 13, 2025 at 02:12:30PM +0800, kernel test robot wrote:
> Hi Jeremy,
>
> kernel test robot noticed the following build errors:
>
> [auto build test ERROR on arm64/for-next/core]
> [also build test ERROR on perf-tools-next/perf-tools-next tip/perf/core perf-tools/perf-tools linus/master v6.17-rc1 next-20250812]
> [cannot apply to acme/perf/core]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url: https://github.com/intel-lab-lkp/linux/commits/Jeremy-Linton/arm64-probes-Break-ret-out-from-bl-blr/20250811-221529
> base: https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/core
> patch link: https://lore.kernel.org/r/20250811141010.741989-6-jeremy.linton%40arm.com
> patch subject: [PATCH v5 5/7] arm64: uprobes: Add GCS support to uretprobes
> config: arm64-randconfig-r111-20250813 (https://download.01.org/0day-ci/archive/20250813/202508131334.FfoZQ27h-lkp@intel.com/config)
> compiler: aarch64-linux-gcc (GCC) 13.4.0
> reproduce: (https://download.01.org/0day-ci/archive/20250813/202508131334.FfoZQ27h-lkp@intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202508131334.FfoZQ27h-lkp@intel.com/
>
> All errors (new ones prefixed by >>):
>
> arch/arm64/kernel/probes/uprobes.c: In function 'arch_uretprobe_hijack_return_addr':
> >> arch/arm64/kernel/probes/uprobes.c:171:33: error: implicit declaration of function 'get_user_gcs'; did you mean 'put_user_gcs'? [-Werror=implicit-function-declaration]
> 171 | gcs_ret_vaddr = get_user_gcs((unsigned long __user *)gcspr, &err);
> | ^~~~~~~~~~~~
> | put_user_gcs
> cc1: some warnings being treated as errors
I guess that's explained by patch 3 not being updated.
--
Catalin
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2025-08-15 14:11 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-11 14:10 [PATCH v5 0/7] arm64: Enable UPROBES with GCS Jeremy Linton
2025-08-11 14:10 ` [PATCH v5 1/7] arm64: probes: Break ret out from bl/blr Jeremy Linton
2025-08-11 14:10 ` [PATCH v5 2/7] arm64: uaccess: Move existing GCS accessors definitions to gcs.h Jeremy Linton
2025-08-11 14:10 ` [PATCH v5 3/7] arm64: uaccess: Add additional userspace GCS accessors Jeremy Linton
2025-08-11 14:40 ` Jeremy Linton
2025-08-11 14:10 ` [PATCH v5 4/7] arm64: probes: Add GCS support to bl/blr/ret Jeremy Linton
2025-08-15 14:08 ` Catalin Marinas
2025-08-11 14:10 ` [PATCH v5 5/7] arm64: uprobes: Add GCS support to uretprobes Jeremy Linton
2025-08-13 6:12 ` kernel test robot
2025-08-15 14:10 ` Catalin Marinas
2025-08-11 14:10 ` [PATCH v5 6/7] arm64: Kconfig: Remove GCS restrictions on UPROBES Jeremy Linton
2025-08-11 14:10 ` [PATCH v5 7/7] uprobes: uprobe_warn should use passed task Jeremy Linton
2025-08-15 14:09 ` Catalin Marinas
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).