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
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
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
© 2016 - 2025 Red Hat, Inc.