Skip to content

Commit d0ee8d5

Browse files
mhiramatgregkh
authored andcommitted
arm: kprobes: Fix the return address of multiple kretprobes
[ Upstream commit 0655317 ] This is arm port of commit 737480a ("kprobes/x86: Fix the return address of multiple kretprobes"). Fix the return address of subsequent kretprobes when multiple kretprobes are set on the same function. For example: # cd /sys/kernel/debug/tracing # echo "r:event1 sys_symlink" > kprobe_events # echo "r:event2 sys_symlink" >> kprobe_events # echo 1 > events/kprobes/enable # ln -s /tmp/foo /tmp/bar (without this patch) # cat trace | grep -v ^# ln-82 [000] dn.2 68.446525: event1: (kretprobe_trampoline+0x0/0x18 <- SyS_symlink) ln-82 [000] dn.2 68.447831: event2: (ret_fast_syscall+0x0/0x1c <- SyS_symlink) (with this patch) # cat trace | grep -v ^# ln-81 [000] dn.1 39.463469: event1: (ret_fast_syscall+0x0/0x1c <- SyS_symlink) ln-81 [000] dn.1 39.464701: event2: (ret_fast_syscall+0x0/0x1c <- SyS_symlink) Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org> Cc: KUMANO Syuhei <kumano.prog@gmail.com> Signed-off-by: Jon Medhurst <tixy@linaro.org> Signed-off-by: Sasha Levin <alexander.levin@verizon.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 6e2a694 commit d0ee8d5

1 file changed

Lines changed: 22 additions & 2 deletions

File tree

arch/arm/probes/kprobes/core.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,7 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs)
433433
struct hlist_node *tmp;
434434
unsigned long flags, orig_ret_address = 0;
435435
unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
436+
kprobe_opcode_t *correct_ret_addr = NULL;
436437

437438
INIT_HLIST_HEAD(&empty_rp);
438439
kretprobe_hash_lock(current, &head, &flags);
@@ -455,14 +456,34 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs)
455456
/* another task is sharing our hash bucket */
456457
continue;
457458

459+
orig_ret_address = (unsigned long)ri->ret_addr;
460+
461+
if (orig_ret_address != trampoline_address)
462+
/*
463+
* This is the real return address. Any other
464+
* instances associated with this task are for
465+
* other calls deeper on the call stack
466+
*/
467+
break;
468+
}
469+
470+
kretprobe_assert(ri, orig_ret_address, trampoline_address);
471+
472+
correct_ret_addr = ri->ret_addr;
473+
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
474+
if (ri->task != current)
475+
/* another task is sharing our hash bucket */
476+
continue;
477+
478+
orig_ret_address = (unsigned long)ri->ret_addr;
458479
if (ri->rp && ri->rp->handler) {
459480
__this_cpu_write(current_kprobe, &ri->rp->kp);
460481
get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
482+
ri->ret_addr = correct_ret_addr;
461483
ri->rp->handler(ri, regs);
462484
__this_cpu_write(current_kprobe, NULL);
463485
}
464486

465-
orig_ret_address = (unsigned long)ri->ret_addr;
466487
recycle_rp_inst(ri, &empty_rp);
467488

468489
if (orig_ret_address != trampoline_address)
@@ -474,7 +495,6 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs)
474495
break;
475496
}
476497

477-
kretprobe_assert(ri, orig_ret_address, trampoline_address);
478498
kretprobe_hash_unlock(current, &flags);
479499

480500
hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {

0 commit comments

Comments
 (0)