[PATCH v5 5/7] arm64: uprobes: Add GCS support to uretprobes

Jeremy Linton posted 7 patches 1 month, 3 weeks ago
There is a newer version of this series
[PATCH v5 5/7] arm64: uprobes: Add GCS support to uretprobes
Posted by Jeremy Linton 1 month, 3 weeks ago
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
Re: [PATCH v5 5/7] arm64: uprobes: Add GCS support to uretprobes
Posted by kernel test robot 1 month, 3 weeks ago
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
Re: [PATCH v5 5/7] arm64: uprobes: Add GCS support to uretprobes
Posted by Catalin Marinas 1 month, 2 weeks ago
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