@@ -56,8 +56,10 @@ static inline void update_lr(struct pt_regs *regs, long addr)
if (user_mode(regs) && task_gcs_el0_enabled(current)) {
push_user_gcs(addr + 4, &err);
- if (err)
+ if (err) {
+ uprobe_warn(current, "GCS stack push failure");
force_sig(SIGSEGV);
+ }
}
procedure_link_pointer_set(regs, addr + 4);
}
@@ -160,8 +162,10 @@ simulate_ret(u32 opcode, long addr, struct pt_regs *regs)
if (user_mode(regs) && task_gcs_el0_enabled(current)) {
ret_addr = pop_user_gcs(&err);
- if (err || ret_addr != procedure_link_pointer(regs))
+ if (err || ret_addr != procedure_link_pointer(regs)) {
+ uprobe_warn(current, "GCS RET address mismatch");
force_sig(SIGSEGV);
+ }
}
}
@@ -54,6 +54,7 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
switch (arm_probe_decode_insn(insn, &auprobe->api)) {
case INSN_REJECTED:
+ uprobe_warn(current, "Unsupported instruction at probe location");
return -EINVAL;
case INSN_GOOD_NO_SLOT:
@@ -169,6 +170,7 @@ arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
gcspr = read_sysreg_s(SYS_GCSPR_EL0);
gcs_ret_vaddr = load_user_gcs((unsigned long __user *)gcspr, &err);
if (err) {
+ uprobe_warn(current, "GCS stack not available for retprobe");
force_sig(SIGSEGV);
goto out;
}
@@ -180,11 +182,13 @@ arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
* a GCS exception.
*/
if (gcs_ret_vaddr != orig_ret_vaddr) {
+ uprobe_warn(current, "LR/GCS mismatch, likely due to incorrectly placed retprobe");
orig_ret_vaddr = -1;
goto out;
}
put_user_gcs(trampoline_vaddr, (unsigned long __user *) gcspr, &err);
if (err) {
+ uprobe_warn(current, "GCS stack update failure during retprobe");
force_sig(SIGSEGV);
goto out;
}
@@ -185,6 +185,7 @@ struct uprobes_state {
};
extern void __init uprobes_init(void);
+extern void uprobe_warn(struct task_struct *t, const char *msg);
extern int set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr);
extern int set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr);
extern bool is_swbp_insn(uprobe_opcode_t *insn);
@@ -118,7 +118,7 @@ struct xol_area {
unsigned long vaddr; /* Page(s) of instruction slots */
};
-static void uprobe_warn(struct task_struct *t, const char *msg)
+void uprobe_warn(struct task_struct *t, const char *msg)
{
pr_warn("uprobe: %s:%d failed to %s\n", current->comm, current->pid, msg);
}
The uprobe_warn function is limited to the uprobe core, but the functionality is useful to report arch specific errors. Drop the static so it can be used in those code paths. Signed-off-by: Jeremy Linton <jeremy.linton@arm.com> --- arch/arm64/kernel/probes/simulate-insn.c | 8 ++++++-- arch/arm64/kernel/probes/uprobes.c | 4 ++++ include/linux/uprobes.h | 1 + kernel/events/uprobes.c | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-)