Skip to content

Commit 4a60171

Browse files
jlintonarmwilldeacon
authored andcommitted
arm64: uprobes: Add GCS support to uretprobes
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> Signed-off-by: Jeremy Linton <jeremy.linton@arm.com> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> [will: Add '__force' to gcspr casts in arch_uretprobe_hijack_return_addr()] Signed-off-by: Will Deacon <will@kernel.org>
1 parent efb07ac commit 4a60171

1 file changed

Lines changed: 33 additions & 0 deletions

File tree

arch/arm64/kernel/probes/uprobes.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <linux/ptrace.h>
77
#include <linux/uprobes.h>
88
#include <asm/cacheflush.h>
9+
#include <asm/gcs.h>
910

1011
#include "decode-insn.h"
1112

@@ -159,11 +160,43 @@ arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
159160
struct pt_regs *regs)
160161
{
161162
unsigned long orig_ret_vaddr;
163+
unsigned long gcs_ret_vaddr;
164+
int err = 0;
165+
u64 gcspr;
162166

163167
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((__force 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, (__force unsigned long __user *)gcspr, &err);
190+
if (err) {
191+
force_sig(SIGSEGV);
192+
goto out;
193+
}
194+
}
195+
164196
/* Replace the return addr with trampoline addr */
165197
procedure_link_pointer_set(regs, trampoline_vaddr);
166198

199+
out:
167200
return orig_ret_vaddr;
168201
}
169202

0 commit comments

Comments
 (0)