Skip to content

Commit c9becf5

Browse files
Masami HiramatsuLinus Torvalds
authored andcommitted
[PATCH] kretprobe: kretprobe-booster
In normal operation, kretprobe makes a target function return to trampoline code. A kprobe (called trampoline_probe) has been inserted in the trampoline code. When the kernel hits this kprobe, it calls kretprobe's handler and it returns to the original return address. Kretprobe-booster removes the trampoline_probe. It allows the trampoline code to call kretprobe's handler directly instead of invoking kprobe. The trampoline code returns to the original return address. (changelog from Chuck Ebbert <[email protected]> - thanks ;)) Signed-off-by: Masami Hiramatsu <[email protected]> Cc: Prasanna S Panchamukhi <[email protected]> Cc: Ananth N Mavinakayanahalli <[email protected]> Cc: Anil S Keshavamurthy <[email protected]> Cc: David S. Miller <[email protected]> Cc: Chuck Ebbert <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 311ac88 commit c9becf5

File tree

1 file changed

+39
-22
lines changed

1 file changed

+39
-22
lines changed

arch/i386/kernel/kprobes.c

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -333,17 +333,44 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
333333
* here. When a retprobed function returns, this probe is hit and
334334
* trampoline_probe_handler() runs, calling the kretprobe's handler.
335335
*/
336-
void kretprobe_trampoline_holder(void)
336+
void __kprobes kretprobe_trampoline_holder(void)
337337
{
338-
asm volatile ( ".global kretprobe_trampoline\n"
338+
asm volatile ( ".global kretprobe_trampoline\n"
339339
"kretprobe_trampoline: \n"
340-
"nop\n");
341-
}
340+
" pushf\n"
341+
/* skip cs, eip, orig_eax, es, ds */
342+
" subl $20, %esp\n"
343+
" pushl %eax\n"
344+
" pushl %ebp\n"
345+
" pushl %edi\n"
346+
" pushl %esi\n"
347+
" pushl %edx\n"
348+
" pushl %ecx\n"
349+
" pushl %ebx\n"
350+
" movl %esp, %eax\n"
351+
" call trampoline_handler\n"
352+
/* move eflags to cs */
353+
" movl 48(%esp), %edx\n"
354+
" movl %edx, 44(%esp)\n"
355+
/* save true return address on eflags */
356+
" movl %eax, 48(%esp)\n"
357+
" popl %ebx\n"
358+
" popl %ecx\n"
359+
" popl %edx\n"
360+
" popl %esi\n"
361+
" popl %edi\n"
362+
" popl %ebp\n"
363+
" popl %eax\n"
364+
/* skip eip, orig_eax, es, ds */
365+
" addl $16, %esp\n"
366+
" popf\n"
367+
" ret\n");
368+
}
342369

343370
/*
344-
* Called when we hit the probe point at kretprobe_trampoline
371+
* Called from kretprobe_trampoline
345372
*/
346-
int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
373+
fastcall void *__kprobes trampoline_handler(struct pt_regs *regs)
347374
{
348375
struct kretprobe_instance *ri = NULL;
349376
struct hlist_head *head;
@@ -372,8 +399,11 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
372399
/* another task is sharing our hash bucket */
373400
continue;
374401

375-
if (ri->rp && ri->rp->handler)
402+
if (ri->rp && ri->rp->handler){
403+
__get_cpu_var(current_kprobe) = &ri->rp->kp;
376404
ri->rp->handler(ri, regs);
405+
__get_cpu_var(current_kprobe) = NULL;
406+
}
377407

378408
orig_ret_address = (unsigned long)ri->ret_addr;
379409
recycle_rp_inst(ri);
@@ -388,18 +418,10 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
388418
}
389419

390420
BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
391-
regs->eip = orig_ret_address;
392421

393-
reset_current_kprobe();
394422
spin_unlock_irqrestore(&kretprobe_lock, flags);
395-
preempt_enable_no_resched();
396423

397-
/*
398-
* By returning a non-zero value, we are telling
399-
* kprobe_handler() that we don't want the post_handler
400-
* to run (and have re-enabled preemption)
401-
*/
402-
return 1;
424+
return (void*)orig_ret_address;
403425
}
404426

405427
/*
@@ -646,12 +668,7 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
646668
return 0;
647669
}
648670

649-
static struct kprobe trampoline_p = {
650-
.addr = (kprobe_opcode_t *) &kretprobe_trampoline,
651-
.pre_handler = trampoline_probe_handler
652-
};
653-
654671
int __init arch_init_kprobes(void)
655672
{
656-
return register_kprobe(&trampoline_p);
673+
return 0;
657674
}

0 commit comments

Comments
 (0)