Commit 1c689070 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'perf-kprobes-2020-10-12' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf/kprobes updates from Ingo Molnar:
 "This prepares to unify the kretprobe trampoline handler and make
  kretprobe lockless (those patches are still work in progress)"

* tag 'perf-kprobes-2020-10-12' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  kprobes: Fix to check probe enabled before disarm_kprobe_ftrace()
  kprobes: Make local functions static
  kprobes: Free kretprobe_instance with RCU callback
  kprobes: Remove NMI context check
  sparc: kprobes: Use generic kretprobe trampoline handler
  sh: kprobes: Use generic kretprobe trampoline handler
  s390: kprobes: Use generic kretprobe trampoline handler
  powerpc: kprobes: Use generic kretprobe trampoline handler
  parisc: kprobes: Use generic kretprobe trampoline handler
  mips: kprobes: Use generic kretprobe trampoline handler
  ia64: kprobes: Use generic kretprobe trampoline handler
  csky: kprobes: Use generic kretprobe trampoline handler
  arc: kprobes: Use generic kretprobe trampoline handler
  arm64: kprobes: Use generic kretprobe trampoline handler
  arm: kprobes: Use generic kretprobe trampoline handler
  x86/kprobes: Use generic kretprobe trampoline handler
  kprobes: Add generic kretprobe trampoline handler
parents 3bff6112 bcb53209
...@@ -388,6 +388,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, ...@@ -388,6 +388,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
{ {
ri->ret_addr = (kprobe_opcode_t *) regs->blink; ri->ret_addr = (kprobe_opcode_t *) regs->blink;
ri->fp = NULL;
/* Replace the return addr with trampoline addr */ /* Replace the return addr with trampoline addr */
regs->blink = (unsigned long)&kretprobe_trampoline; regs->blink = (unsigned long)&kretprobe_trampoline;
...@@ -396,58 +397,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, ...@@ -396,58 +397,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
static int __kprobes trampoline_probe_handler(struct kprobe *p, static int __kprobes trampoline_probe_handler(struct kprobe *p,
struct pt_regs *regs) struct pt_regs *regs)
{ {
struct kretprobe_instance *ri = NULL; regs->ret = __kretprobe_trampoline_handler(regs, &kretprobe_trampoline, NULL);
struct hlist_head *head, empty_rp;
struct hlist_node *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
INIT_HLIST_HEAD(&empty_rp);
kretprobe_hash_lock(current, &head, &flags);
/*
* It is possible to have multiple instances associated with a given
* task either because an multiple functions in the call path
* have a return probe installed on them, and/or more than one return
* return probe was registered for a target function.
*
* We can handle this because:
* - instances are always inserted at the head of the list
* - when multiple return probes are registered for the same
* function, the first instance's ret_addr will point to the
* real return address, and all the rest will point to
* kretprobe_trampoline
*/
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
if (ri->rp && ri->rp->handler)
ri->rp->handler(ri, regs);
orig_ret_address = (unsigned long)ri->ret_addr;
recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address) {
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
}
kretprobe_assert(ri, orig_ret_address, trampoline_address);
regs->ret = orig_ret_address;
kretprobe_hash_unlock(current, &flags);
hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
hlist_del(&ri->hlist);
kfree(ri);
}
/* By returning a non zero value, we are telling the kprobe handler /* By returning a non zero value, we are telling the kprobe handler
* that we don't want the post_handler to run * that we don't want the post_handler to run
......
...@@ -413,87 +413,15 @@ void __naked __kprobes kretprobe_trampoline(void) ...@@ -413,87 +413,15 @@ void __naked __kprobes kretprobe_trampoline(void)
/* Called from kretprobe_trampoline */ /* Called from kretprobe_trampoline */
static __used __kprobes void *trampoline_handler(struct pt_regs *regs) static __used __kprobes void *trampoline_handler(struct pt_regs *regs)
{ {
struct kretprobe_instance *ri = NULL; return (void *)kretprobe_trampoline_handler(regs, &kretprobe_trampoline,
struct hlist_head *head, empty_rp; (void *)regs->ARM_fp);
struct hlist_node *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
kprobe_opcode_t *correct_ret_addr = NULL;
INIT_HLIST_HEAD(&empty_rp);
kretprobe_hash_lock(current, &head, &flags);
/*
* It is possible to have multiple instances associated with a given
* task either because multiple functions in the call path have
* a return probe installed on them, and/or more than one return
* probe was registered for a target function.
*
* We can handle this because:
* - instances are always inserted at the head of the list
* - when multiple return probes are registered for the same
* function, the first instance's ret_addr will point to the
* real return address, and all the rest will point to
* kretprobe_trampoline
*/
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
orig_ret_address = (unsigned long)ri->ret_addr;
if (orig_ret_address != trampoline_address)
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
kretprobe_assert(ri, orig_ret_address, trampoline_address);
correct_ret_addr = ri->ret_addr;
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
orig_ret_address = (unsigned long)ri->ret_addr;
if (ri->rp && ri->rp->handler) {
__this_cpu_write(current_kprobe, &ri->rp->kp);
get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
ri->ret_addr = correct_ret_addr;
ri->rp->handler(ri, regs);
__this_cpu_write(current_kprobe, NULL);
}
recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address)
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
kretprobe_hash_unlock(current, &flags);
hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
hlist_del(&ri->hlist);
kfree(ri);
}
return (void *)orig_ret_address;
} }
void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
struct pt_regs *regs) struct pt_regs *regs)
{ {
ri->ret_addr = (kprobe_opcode_t *)regs->ARM_lr; ri->ret_addr = (kprobe_opcode_t *)regs->ARM_lr;
ri->fp = (void *)regs->ARM_fp;
/* Replace the return addr with trampoline addr. */ /* Replace the return addr with trampoline addr. */
regs->ARM_lr = (unsigned long)&kretprobe_trampoline; regs->ARM_lr = (unsigned long)&kretprobe_trampoline;
......
...@@ -464,87 +464,15 @@ int __init arch_populate_kprobe_blacklist(void) ...@@ -464,87 +464,15 @@ int __init arch_populate_kprobe_blacklist(void)
void __kprobes __used *trampoline_probe_handler(struct pt_regs *regs) void __kprobes __used *trampoline_probe_handler(struct pt_regs *regs)
{ {
struct kretprobe_instance *ri = NULL; return (void *)kretprobe_trampoline_handler(regs, &kretprobe_trampoline,
struct hlist_head *head, empty_rp; (void *)kernel_stack_pointer(regs));
struct hlist_node *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address =
(unsigned long)&kretprobe_trampoline;
kprobe_opcode_t *correct_ret_addr = NULL;
INIT_HLIST_HEAD(&empty_rp);
kretprobe_hash_lock(current, &head, &flags);
/*
* It is possible to have multiple instances associated with a given
* task either because multiple functions in the call path have
* return probes installed on them, and/or more than one
* return probe was registered for a target function.
*
* We can handle this because:
* - instances are always pushed into the head of the list
* - when multiple return probes are registered for the same
* function, the (chronologically) first instance's ret_addr
* will be the real return address, and all the rest will
* point to kretprobe_trampoline.
*/
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
orig_ret_address = (unsigned long)ri->ret_addr;
if (orig_ret_address != trampoline_address)
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
kretprobe_assert(ri, orig_ret_address, trampoline_address);
correct_ret_addr = ri->ret_addr;
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
orig_ret_address = (unsigned long)ri->ret_addr;
if (ri->rp && ri->rp->handler) {
__this_cpu_write(current_kprobe, &ri->rp->kp);
get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
ri->ret_addr = correct_ret_addr;
ri->rp->handler(ri, regs);
__this_cpu_write(current_kprobe, NULL);
}
recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address)
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
kretprobe_hash_unlock(current, &flags);
hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
hlist_del(&ri->hlist);
kfree(ri);
}
return (void *)orig_ret_address;
} }
void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
struct pt_regs *regs) struct pt_regs *regs)
{ {
ri->ret_addr = (kprobe_opcode_t *)regs->regs[30]; ri->ret_addr = (kprobe_opcode_t *)regs->regs[30];
ri->fp = (void *)kernel_stack_pointer(regs);
/* replace return addr (x30) with trampoline */ /* replace return addr (x30) with trampoline */
regs->regs[30] = (long)&kretprobe_trampoline; regs->regs[30] = (long)&kretprobe_trampoline;
......
...@@ -404,87 +404,14 @@ int __init arch_populate_kprobe_blacklist(void) ...@@ -404,87 +404,14 @@ int __init arch_populate_kprobe_blacklist(void)
void __kprobes __used *trampoline_probe_handler(struct pt_regs *regs) void __kprobes __used *trampoline_probe_handler(struct pt_regs *regs)
{ {
struct kretprobe_instance *ri = NULL; return (void *)kretprobe_trampoline_handler(regs, &kretprobe_trampoline, NULL);
struct hlist_head *head, empty_rp;
struct hlist_node *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address =
(unsigned long)&kretprobe_trampoline;
kprobe_opcode_t *correct_ret_addr = NULL;
INIT_HLIST_HEAD(&empty_rp);
kretprobe_hash_lock(current, &head, &flags);
/*
* It is possible to have multiple instances associated with a given
* task either because multiple functions in the call path have
* return probes installed on them, and/or more than one
* return probe was registered for a target function.
*
* We can handle this because:
* - instances are always pushed into the head of the list
* - when multiple return probes are registered for the same
* function, the (chronologically) first instance's ret_addr
* will be the real return address, and all the rest will
* point to kretprobe_trampoline.
*/
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
orig_ret_address = (unsigned long)ri->ret_addr;
if (orig_ret_address != trampoline_address)
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
kretprobe_assert(ri, orig_ret_address, trampoline_address);
correct_ret_addr = ri->ret_addr;
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
orig_ret_address = (unsigned long)ri->ret_addr;
if (ri->rp && ri->rp->handler) {
__this_cpu_write(current_kprobe, &ri->rp->kp);
get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
ri->ret_addr = correct_ret_addr;
ri->rp->handler(ri, regs);
__this_cpu_write(current_kprobe, NULL);
}
recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address)
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
kretprobe_hash_unlock(current, &flags);
hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
hlist_del(&ri->hlist);
kfree(ri);
}
return (void *)orig_ret_address;
} }
void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
struct pt_regs *regs) struct pt_regs *regs)
{ {
ri->ret_addr = (kprobe_opcode_t *)regs->lr; ri->ret_addr = (kprobe_opcode_t *)regs->lr;
ri->fp = NULL;
regs->lr = (unsigned long) &kretprobe_trampoline; regs->lr = (unsigned long) &kretprobe_trampoline;
} }
......
...@@ -396,83 +396,9 @@ static void kretprobe_trampoline(void) ...@@ -396,83 +396,9 @@ static void kretprobe_trampoline(void)
{ {
} }
/*
* At this point the target function has been tricked into
* returning into our trampoline. Lookup the associated instance
* and then:
* - call the handler function
* - cleanup by marking the instance as unused
* - long jump back to the original return address
*/
int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
{ {
struct kretprobe_instance *ri = NULL; regs->cr_iip = __kretprobe_trampoline_handler(regs, kretprobe_trampoline, NULL);
struct hlist_head *head, empty_rp;
struct hlist_node *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address =
((struct fnptr *)kretprobe_trampoline)->ip;
INIT_HLIST_HEAD(&empty_rp);
kretprobe_hash_lock(current, &head, &flags);
/*
* It is possible to have multiple instances associated with a given
* task either because an multiple functions in the call path
* have a return probe installed on them, and/or more than one return
* return probe was registered for a target function.
*
* We can handle this because:
* - instances are always inserted at the head of the list
* - when multiple return probes are registered for the same
* function, the first instance's ret_addr will point to the
* real return address, and all the rest will point to
* kretprobe_trampoline
*/
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
orig_ret_address = (unsigned long)ri->ret_addr;
if (orig_ret_address != trampoline_address)
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
regs->cr_iip = orig_ret_address;
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
if (ri->rp && ri->rp->handler)
ri->rp->handler(ri, regs);
orig_ret_address = (unsigned long)ri->ret_addr;
recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address)
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
kretprobe_assert(ri, orig_ret_address, trampoline_address);
kretprobe_hash_unlock(current, &flags);
hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
hlist_del(&ri->hlist);
kfree(ri);
}
/* /*
* By returning a non-zero value, we are telling * By returning a non-zero value, we are telling
* kprobe_handler() that we don't want the post_handler * kprobe_handler() that we don't want the post_handler
...@@ -485,6 +411,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, ...@@ -485,6 +411,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
struct pt_regs *regs) struct pt_regs *regs)
{ {
ri->ret_addr = (kprobe_opcode_t *)regs->b0; ri->ret_addr = (kprobe_opcode_t *)regs->b0;
ri->fp = NULL;
/* Replace the return addr with trampoline addr */ /* Replace the return addr with trampoline addr */
regs->b0 = ((struct fnptr *)kretprobe_trampoline)->ip; regs->b0 = ((struct fnptr *)kretprobe_trampoline)->ip;
......
...@@ -477,6 +477,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, ...@@ -477,6 +477,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
struct pt_regs *regs) struct pt_regs *regs)
{ {
ri->ret_addr = (kprobe_opcode_t *) regs->regs[31]; ri->ret_addr = (kprobe_opcode_t *) regs->regs[31];
ri->fp = NULL;
/* Replace the return addr with trampoline addr */ /* Replace the return addr with trampoline addr */
regs->regs[31] = (unsigned long)kretprobe_trampoline; regs->regs[31] = (unsigned long)kretprobe_trampoline;
...@@ -488,57 +489,8 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, ...@@ -488,57 +489,8 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
static int __kprobes trampoline_probe_handler(struct kprobe *p, static int __kprobes trampoline_probe_handler(struct kprobe *p,
struct pt_regs *regs) struct pt_regs *regs)
{ {
struct kretprobe_instance *ri = NULL; instruction_pointer(regs) = __kretprobe_trampoline_handler(regs,
struct hlist_head *head, empty_rp; kretprobe_trampoline, NULL);
struct hlist_node *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address = (unsigned long)kretprobe_trampoline;
INIT_HLIST_HEAD(&empty_rp);
kretprobe_hash_lock(current, &head, &flags);
/*
* It is possible to have multiple instances associated with a given
* task either because an multiple functions in the call path
* have a return probe installed on them, and/or more than one return
* return probe was registered for a target function.
*
* We can handle this because:
* - instances are always inserted at the head of the list
* - when multiple return probes are registered for the same
* function, the first instance's ret_addr will point to the
* real return address, and all the rest will point to
* kretprobe_trampoline
*/
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
if (ri->rp && ri->rp->handler)
ri->rp->handler(ri, regs);
orig_ret_address = (unsigned long)ri->ret_addr;
recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address)
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
kretprobe_assert(ri, orig_ret_address, trampoline_address);
instruction_pointer(regs) = orig_ret_address;
kretprobe_hash_unlock(current, &flags);
hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
hlist_del(&ri->hlist);
kfree(ri);
}
/* /*
* By returning a non-zero value, we are telling * By returning a non-zero value, we are telling
* kprobe_handler() that we don't want the post_handler * kprobe_handler() that we don't want the post_handler
......
...@@ -191,80 +191,11 @@ static struct kprobe trampoline_p = { ...@@ -191,80 +191,11 @@ static struct kprobe trampoline_p = {
static int __kprobes trampoline_probe_handler(struct kprobe *p, static int __kprobes trampoline_probe_handler(struct kprobe *p,
struct pt_regs *regs) struct pt_regs *regs)
{ {
struct kretprobe_instance *ri = NULL; unsigned long orig_ret_address;
struct hlist_head *head, empty_rp;
struct hlist_node *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address = (unsigned long)trampoline_p.addr;
kprobe_opcode_t *correct_ret_addr = NULL;
INIT_HLIST_HEAD(&empty_rp);
kretprobe_hash_lock(current, &head, &flags);
/*
* It is possible to have multiple instances associated with a given
* task either because multiple functions in the call path have
* a return probe installed on them, and/or more than one return
* probe was registered for a target function.
*
* We can handle this because:
* - instances are always inserted at the head of the list
* - when multiple return probes are registered for the same
* function, the first instance's ret_addr will point to the
* real return address, and all the rest will point to
* kretprobe_trampoline
*/
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
orig_ret_address = (unsigned long)ri->ret_addr;
if (orig_ret_address != trampoline_address)
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
kretprobe_assert(ri, orig_ret_address, trampoline_address);
correct_ret_addr = ri->ret_addr;
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
orig_ret_address = (unsigned long)ri->ret_addr;
if (ri->rp && ri->rp->handler) {
__this_cpu_write(current_kprobe, &ri->rp->kp);
get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
ri->ret_addr = correct_ret_addr;
ri->rp->handler(ri, regs);
__this_cpu_write(current_kprobe, NULL);
}
recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address)
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
kretprobe_hash_unlock(current, &flags); orig_ret_address = __kretprobe_trampoline_handler(regs, trampoline_p.addr, NULL);
hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
hlist_del(&ri->hlist);
kfree(ri);
}
instruction_pointer_set(regs, orig_ret_address); instruction_pointer_set(regs, orig_ret_address);
return 1; return 1;
} }
...@@ -272,6 +203,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, ...@@ -272,6 +203,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
struct pt_regs *regs) struct pt_regs *regs)
{ {
ri->ret_addr = (kprobe_opcode_t *)regs->gr[2]; ri->ret_addr = (kprobe_opcode_t *)regs->gr[2];
ri->fp = NULL;
/* Replace the return addr with trampoline addr. */ /* Replace the return addr with trampoline addr. */
regs->gr[2] = (unsigned long)trampoline_p.addr; regs->gr[2] = (unsigned long)trampoline_p.addr;
......
...@@ -218,6 +218,7 @@ bool arch_kprobe_on_func_entry(unsigned long offset) ...@@ -218,6 +218,7 @@ bool arch_kprobe_on_func_entry(unsigned long offset)
void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs)
{ {
ri->ret_addr = (kprobe_opcode_t *)regs->link; ri->ret_addr = (kprobe_opcode_t *)regs->link;
ri->fp = NULL;
/* Replace the return addr with trampoline addr */ /* Replace the return addr with trampoline addr */
regs->link = (unsigned long)kretprobe_trampoline; regs->link = (unsigned long)kretprobe_trampoline;
...@@ -396,50 +397,9 @@ asm(".global kretprobe_trampoline\n" ...@@ -396,50 +397,9 @@ asm(".global kretprobe_trampoline\n"
*/ */
static int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) static int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
{ {
struct kretprobe_instance *ri = NULL; unsigned long orig_ret_address;
struct hlist_head *head, empty_rp;
struct hlist_node *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
INIT_HLIST_HEAD(&empty_rp);
kretprobe_hash_lock(current, &head, &flags);
/*
* It is possible to have multiple instances associated with a given
* task either because an multiple functions in the call path
* have a return probe installed on them, and/or more than one return
* return probe was registered for a target function.
*
* We can handle this because:
* - instances are always inserted at the head of the list
* - when multiple return probes are registered for the same
* function, the first instance's ret_addr will point to the
* real return address, and all the rest will point to
* kretprobe_trampoline
*/
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
if (ri->rp && ri->rp->handler)
ri->rp->handler(ri, regs);
orig_ret_address = (unsigned long)ri->ret_addr;
recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address)
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
kretprobe_assert(ri, orig_ret_address, trampoline_address);
orig_ret_address = __kretprobe_trampoline_handler(regs, &kretprobe_trampoline, NULL);
/* /*
* We get here through one of two paths: * We get here through one of two paths:
* 1. by taking a trap -> kprobe_handler() -> here * 1. by taking a trap -> kprobe_handler() -> here
...@@ -458,13 +418,6 @@ static int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) ...@@ -458,13 +418,6 @@ static int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
regs->nip = orig_ret_address - 4; regs->nip = orig_ret_address - 4;
regs->link = orig_ret_address; regs->link = orig_ret_address;
kretprobe_hash_unlock(current, &flags);
hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
hlist_del(&ri->hlist);
kfree(ri);
}
return 0; return 0;
} }
NOKPROBE_SYMBOL(trampoline_probe_handler); NOKPROBE_SYMBOL(trampoline_probe_handler);
......
...@@ -228,6 +228,7 @@ NOKPROBE_SYMBOL(pop_kprobe); ...@@ -228,6 +228,7 @@ NOKPROBE_SYMBOL(pop_kprobe);
void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs)
{ {
ri->ret_addr = (kprobe_opcode_t *) regs->gprs[14]; ri->ret_addr = (kprobe_opcode_t *) regs->gprs[14];
ri->fp = NULL;
/* Replace the return addr with trampoline addr */ /* Replace the return addr with trampoline addr */
regs->gprs[14] = (unsigned long) &kretprobe_trampoline; regs->gprs[14] = (unsigned long) &kretprobe_trampoline;
...@@ -331,83 +332,7 @@ static void __used kretprobe_trampoline_holder(void) ...@@ -331,83 +332,7 @@ static void __used kretprobe_trampoline_holder(void)
*/ */
static int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) static int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
{ {
struct kretprobe_instance *ri; regs->psw.addr = __kretprobe_trampoline_handler(regs, &kretprobe_trampoline, NULL);
struct hlist_head *head, empty_rp;
struct hlist_node *tmp;
unsigned long flags, orig_ret_address;
unsigned long trampoline_address;
kprobe_opcode_t *correct_ret_addr;
INIT_HLIST_HEAD(&empty_rp);
kretprobe_hash_lock(current, &head, &flags);
/*
* It is possible to have multiple instances associated with a given
* task either because an multiple functions in the call path
* have a return probe installed on them, and/or more than one return
* return probe was registered for a target function.
*
* We can handle this because:
* - instances are always inserted at the head of the list
* - when multiple return probes are registered for the same
* function, the first instance's ret_addr will point to the
* real return address, and all the rest will point to
* kretprobe_trampoline
*/
ri = NULL;
orig_ret_address = 0;
correct_ret_addr = NULL;
trampoline_address = (unsigned long) &kretprobe_trampoline;
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
orig_ret_address = (unsigned long) ri->ret_addr;
if (orig_ret_address != trampoline_address)
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
kretprobe_assert(ri, orig_ret_address, trampoline_address);
correct_ret_addr = ri->ret_addr;
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
orig_ret_address = (unsigned long) ri->ret_addr;
if (ri->rp && ri->rp->handler) {
ri->ret_addr = correct_ret_addr;
ri->rp->handler(ri, regs);
}
recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address)
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
regs->psw.addr = orig_ret_address;
kretprobe_hash_unlock(current, &flags);
hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
hlist_del(&ri->hlist);
kfree(ri);
}
/* /*
* By returning a non-zero value, we are telling * By returning a non-zero value, we are telling
* kprobe_handler() that we don't want the post_handler * kprobe_handler() that we don't want the post_handler
......
...@@ -204,6 +204,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, ...@@ -204,6 +204,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
struct pt_regs *regs) struct pt_regs *regs)
{ {
ri->ret_addr = (kprobe_opcode_t *) regs->pr; ri->ret_addr = (kprobe_opcode_t *) regs->pr;
ri->fp = NULL;
/* Replace the return addr with trampoline addr */ /* Replace the return addr with trampoline addr */
regs->pr = (unsigned long)kretprobe_trampoline; regs->pr = (unsigned long)kretprobe_trampoline;
...@@ -302,62 +303,9 @@ static void __used kretprobe_trampoline_holder(void) ...@@ -302,62 +303,9 @@ static void __used kretprobe_trampoline_holder(void)
*/ */
int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
{ {
struct kretprobe_instance *ri = NULL; regs->pc = __kretprobe_trampoline_handler(regs, &kretprobe_trampoline, NULL);
struct hlist_head *head, empty_rp;
struct hlist_node *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
INIT_HLIST_HEAD(&empty_rp); return 1;
kretprobe_hash_lock(current, &head, &flags);
/*
* It is possible to have multiple instances associated with a given
* task either because an multiple functions in the call path
* have a return probe installed on them, and/or more then one return
* return probe was registered for a target function.
*
* We can handle this because:
* - instances are always inserted at the head of the list
* - when multiple return probes are registered for the same
* function, the first instance's ret_addr will point to the
* real return address, and all the rest will point to
* kretprobe_trampoline
*/
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
if (ri->rp && ri->rp->handler) {
__this_cpu_write(current_kprobe, &ri->rp->kp);
ri->rp->handler(ri, regs);
__this_cpu_write(current_kprobe, NULL);
}
orig_ret_address = (unsigned long)ri->ret_addr;
recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address)
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
kretprobe_assert(ri, orig_ret_address, trampoline_address);
regs->pc = orig_ret_address;
kretprobe_hash_unlock(current, &flags);
hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
hlist_del(&ri->hlist);
kfree(ri);
}
return orig_ret_address;
} }
static int __kprobes post_kprobe_handler(struct pt_regs *regs) static int __kprobes post_kprobe_handler(struct pt_regs *regs)
......
...@@ -453,6 +453,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, ...@@ -453,6 +453,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
struct pt_regs *regs) struct pt_regs *regs)
{ {
ri->ret_addr = (kprobe_opcode_t *)(regs->u_regs[UREG_RETPC] + 8); ri->ret_addr = (kprobe_opcode_t *)(regs->u_regs[UREG_RETPC] + 8);
ri->fp = NULL;
/* Replace the return addr with trampoline addr */ /* Replace the return addr with trampoline addr */
regs->u_regs[UREG_RETPC] = regs->u_regs[UREG_RETPC] =
...@@ -465,58 +466,12 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, ...@@ -465,58 +466,12 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
static int __kprobes trampoline_probe_handler(struct kprobe *p, static int __kprobes trampoline_probe_handler(struct kprobe *p,
struct pt_regs *regs) struct pt_regs *regs)
{ {
struct kretprobe_instance *ri = NULL; unsigned long orig_ret_address = 0;
struct hlist_head *head, empty_rp;
struct hlist_node *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
INIT_HLIST_HEAD(&empty_rp); orig_ret_address = __kretprobe_trampoline_handler(regs, &kretprobe_trampoline, NULL);
kretprobe_hash_lock(current, &head, &flags);
/*
* It is possible to have multiple instances associated with a given
* task either because an multiple functions in the call path
* have a return probe installed on them, and/or more than one return
* return probe was registered for a target function.
*
* We can handle this because:
* - instances are always inserted at the head of the list
* - when multiple return probes are registered for the same
* function, the first instance's ret_addr will point to the
* real return address, and all the rest will point to
* kretprobe_trampoline
*/
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
if (ri->rp && ri->rp->handler)
ri->rp->handler(ri, regs);
orig_ret_address = (unsigned long)ri->ret_addr;
recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address)
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
kretprobe_assert(ri, orig_ret_address, trampoline_address);
regs->tpc = orig_ret_address; regs->tpc = orig_ret_address;
regs->tnpc = orig_ret_address + 4; regs->tnpc = orig_ret_address + 4;
kretprobe_hash_unlock(current, &flags);
hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
hlist_del(&ri->hlist);
kfree(ri);
}
/* /*
* By returning a non-zero value, we are telling * By returning a non-zero value, we are telling
* kprobe_handler() that we don't want the post_handler * kprobe_handler() that we don't want the post_handler
......
...@@ -767,124 +767,22 @@ asm( ...@@ -767,124 +767,22 @@ asm(
NOKPROBE_SYMBOL(kretprobe_trampoline); NOKPROBE_SYMBOL(kretprobe_trampoline);
STACK_FRAME_NON_STANDARD(kretprobe_trampoline); STACK_FRAME_NON_STANDARD(kretprobe_trampoline);
/* /*
* Called from kretprobe_trampoline * Called from kretprobe_trampoline
*/ */
__used __visible void *trampoline_handler(struct pt_regs *regs) __used __visible void *trampoline_handler(struct pt_regs *regs)
{ {
struct kretprobe_instance *ri = NULL;
struct hlist_head *head, empty_rp;
struct hlist_node *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
kprobe_opcode_t *correct_ret_addr = NULL;
void *frame_pointer;
bool skipped = false;
/*
* Set a dummy kprobe for avoiding kretprobe recursion.
* Since kretprobe never run in kprobe handler, kprobe must not
* be running at this point.
*/
kprobe_busy_begin();
INIT_HLIST_HEAD(&empty_rp);
kretprobe_hash_lock(current, &head, &flags);
/* fixup registers */ /* fixup registers */
regs->cs = __KERNEL_CS; regs->cs = __KERNEL_CS;
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
regs->cs |= get_kernel_rpl(); regs->cs |= get_kernel_rpl();
regs->gs = 0; regs->gs = 0;
#endif #endif
/* We use pt_regs->sp for return address holder. */ regs->ip = (unsigned long)&kretprobe_trampoline;
frame_pointer = &regs->sp;
regs->ip = trampoline_address;
regs->orig_ax = ~0UL; regs->orig_ax = ~0UL;
/* return (void *)kretprobe_trampoline_handler(regs, &kretprobe_trampoline, &regs->sp);
* It is possible to have multiple instances associated with a given
* task either because multiple functions in the call path have
* return probes installed on them, and/or more than one
* return probe was registered for a target function.
*
* We can handle this because:
* - instances are always pushed into the head of the list
* - when multiple return probes are registered for the same
* function, the (chronologically) first instance's ret_addr
* will be the real return address, and all the rest will
* point to kretprobe_trampoline.
*/
hlist_for_each_entry(ri, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
/*
* Return probes must be pushed on this hash list correct
* order (same as return order) so that it can be popped
* correctly. However, if we find it is pushed it incorrect
* order, this means we find a function which should not be
* probed, because the wrong order entry is pushed on the
* path of processing other kretprobe itself.
*/
if (ri->fp != frame_pointer) {
if (!skipped)
pr_warn("kretprobe is stacked incorrectly. Trying to fixup.\n");
skipped = true;
continue;
}
orig_ret_address = (unsigned long)ri->ret_addr;
if (skipped)
pr_warn("%ps must be blacklisted because of incorrect kretprobe order\n",
ri->rp->kp.addr);
if (orig_ret_address != trampoline_address)
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
kretprobe_assert(ri, orig_ret_address, trampoline_address);
correct_ret_addr = ri->ret_addr;
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
if (ri->fp != frame_pointer)
continue;
orig_ret_address = (unsigned long)ri->ret_addr;
if (ri->rp && ri->rp->handler) {
__this_cpu_write(current_kprobe, &ri->rp->kp);
ri->ret_addr = correct_ret_addr;
ri->rp->handler(ri, regs);
__this_cpu_write(current_kprobe, &kprobe_busy);
}
recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address)
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
kretprobe_hash_unlock(current, &flags);
kprobe_busy_end();
hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
hlist_del(&ri->hlist);
kfree(ri);
}
return (void *)orig_ret_address;
} }
NOKPROBE_SYMBOL(trampoline_handler); NOKPROBE_SYMBOL(trampoline_handler);
......
...@@ -156,7 +156,10 @@ struct kretprobe { ...@@ -156,7 +156,10 @@ struct kretprobe {
}; };
struct kretprobe_instance { struct kretprobe_instance {
struct hlist_node hlist; union {
struct hlist_node hlist;
struct rcu_head rcu;
};
struct kretprobe *rp; struct kretprobe *rp;
kprobe_opcode_t *ret_addr; kprobe_opcode_t *ret_addr;
struct task_struct *task; struct task_struct *task;
...@@ -187,10 +190,37 @@ static inline int kprobes_built_in(void) ...@@ -187,10 +190,37 @@ static inline int kprobes_built_in(void)
return 1; return 1;
} }
extern void kprobe_busy_begin(void);
extern void kprobe_busy_end(void);
#ifdef CONFIG_KRETPROBES #ifdef CONFIG_KRETPROBES
extern void arch_prepare_kretprobe(struct kretprobe_instance *ri, extern void arch_prepare_kretprobe(struct kretprobe_instance *ri,
struct pt_regs *regs); struct pt_regs *regs);
extern int arch_trampoline_kprobe(struct kprobe *p); extern int arch_trampoline_kprobe(struct kprobe *p);
/* If the trampoline handler called from a kprobe, use this version */
unsigned long __kretprobe_trampoline_handler(struct pt_regs *regs,
void *trampoline_address,
void *frame_pointer);
static nokprobe_inline
unsigned long kretprobe_trampoline_handler(struct pt_regs *regs,
void *trampoline_address,
void *frame_pointer)
{
unsigned long ret;
/*
* Set a dummy kprobe for avoiding kretprobe recursion.
* Since kretprobe never runs in kprobe handler, no kprobe must
* be running at this point.
*/
kprobe_busy_begin();
ret = __kretprobe_trampoline_handler(regs, trampoline_address, frame_pointer);
kprobe_busy_end();
return ret;
}
#else /* CONFIG_KRETPROBES */ #else /* CONFIG_KRETPROBES */
static inline void arch_prepare_kretprobe(struct kretprobe *rp, static inline void arch_prepare_kretprobe(struct kretprobe *rp,
struct pt_regs *regs) struct pt_regs *regs)
...@@ -204,16 +234,6 @@ static inline int arch_trampoline_kprobe(struct kprobe *p) ...@@ -204,16 +234,6 @@ static inline int arch_trampoline_kprobe(struct kprobe *p)
extern struct kretprobe_blackpoint kretprobe_blacklist[]; extern struct kretprobe_blackpoint kretprobe_blacklist[];
static inline void kretprobe_assert(struct kretprobe_instance *ri,
unsigned long orig_ret_address, unsigned long trampoline_address)
{
if (!orig_ret_address || (orig_ret_address == trampoline_address)) {
printk("kretprobe BUG!: Processing kretprobe %p @ %p\n",
ri->rp, ri->rp->kp.addr);
BUG();
}
}
#ifdef CONFIG_KPROBES_SANITY_TEST #ifdef CONFIG_KPROBES_SANITY_TEST
extern int init_test_probes(void); extern int init_test_probes(void);
#else #else
...@@ -333,10 +353,6 @@ int arch_check_ftrace_location(struct kprobe *p); ...@@ -333,10 +353,6 @@ int arch_check_ftrace_location(struct kprobe *p);
/* Get the kprobe at this addr (if any) - called with preemption disabled */ /* Get the kprobe at this addr (if any) - called with preemption disabled */
struct kprobe *get_kprobe(void *addr); struct kprobe *get_kprobe(void *addr);
void kretprobe_hash_lock(struct task_struct *tsk,
struct hlist_head **head, unsigned long *flags);
void kretprobe_hash_unlock(struct task_struct *tsk, unsigned long *flags);
struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk);
/* kprobe_running() will just return the current_kprobe on this CPU */ /* kprobe_running() will just return the current_kprobe on this CPU */
static inline struct kprobe *kprobe_running(void) static inline struct kprobe *kprobe_running(void)
...@@ -354,10 +370,6 @@ static inline struct kprobe_ctlblk *get_kprobe_ctlblk(void) ...@@ -354,10 +370,6 @@ static inline struct kprobe_ctlblk *get_kprobe_ctlblk(void)
return this_cpu_ptr(&kprobe_ctlblk); return this_cpu_ptr(&kprobe_ctlblk);
} }
extern struct kprobe kprobe_busy;
void kprobe_busy_begin(void);
void kprobe_busy_end(void);
kprobe_opcode_t *kprobe_lookup_name(const char *name, unsigned int offset); kprobe_opcode_t *kprobe_lookup_name(const char *name, unsigned int offset);
int register_kprobe(struct kprobe *p); int register_kprobe(struct kprobe *p);
void unregister_kprobe(struct kprobe *p); void unregister_kprobe(struct kprobe *p);
...@@ -371,7 +383,6 @@ int register_kretprobes(struct kretprobe **rps, int num); ...@@ -371,7 +383,6 @@ int register_kretprobes(struct kretprobe **rps, int num);
void unregister_kretprobes(struct kretprobe **rps, int num); void unregister_kretprobes(struct kretprobe **rps, int num);
void kprobe_flush_task(struct task_struct *tk); void kprobe_flush_task(struct task_struct *tk);
void recycle_rp_inst(struct kretprobe_instance *ri, struct hlist_head *head);
void kprobe_free_init_mem(void); void kprobe_free_init_mem(void);
......
...@@ -1224,8 +1224,7 @@ void kprobes_inc_nmissed_count(struct kprobe *p) ...@@ -1224,8 +1224,7 @@ void kprobes_inc_nmissed_count(struct kprobe *p)
} }
NOKPROBE_SYMBOL(kprobes_inc_nmissed_count); NOKPROBE_SYMBOL(kprobes_inc_nmissed_count);
void recycle_rp_inst(struct kretprobe_instance *ri, static void recycle_rp_inst(struct kretprobe_instance *ri)
struct hlist_head *head)
{ {
struct kretprobe *rp = ri->rp; struct kretprobe *rp = ri->rp;
...@@ -1237,12 +1236,11 @@ void recycle_rp_inst(struct kretprobe_instance *ri, ...@@ -1237,12 +1236,11 @@ void recycle_rp_inst(struct kretprobe_instance *ri,
hlist_add_head(&ri->hlist, &rp->free_instances); hlist_add_head(&ri->hlist, &rp->free_instances);
raw_spin_unlock(&rp->lock); raw_spin_unlock(&rp->lock);
} else } else
/* Unregistering */ kfree_rcu(ri, rcu);
hlist_add_head(&ri->hlist, head);
} }
NOKPROBE_SYMBOL(recycle_rp_inst); NOKPROBE_SYMBOL(recycle_rp_inst);
void kretprobe_hash_lock(struct task_struct *tsk, static void kretprobe_hash_lock(struct task_struct *tsk,
struct hlist_head **head, unsigned long *flags) struct hlist_head **head, unsigned long *flags)
__acquires(hlist_lock) __acquires(hlist_lock)
{ {
...@@ -1264,7 +1262,7 @@ __acquires(hlist_lock) ...@@ -1264,7 +1262,7 @@ __acquires(hlist_lock)
} }
NOKPROBE_SYMBOL(kretprobe_table_lock); NOKPROBE_SYMBOL(kretprobe_table_lock);
void kretprobe_hash_unlock(struct task_struct *tsk, static void kretprobe_hash_unlock(struct task_struct *tsk,
unsigned long *flags) unsigned long *flags)
__releases(hlist_lock) __releases(hlist_lock)
{ {
...@@ -1285,7 +1283,7 @@ __releases(hlist_lock) ...@@ -1285,7 +1283,7 @@ __releases(hlist_lock)
} }
NOKPROBE_SYMBOL(kretprobe_table_unlock); NOKPROBE_SYMBOL(kretprobe_table_unlock);
struct kprobe kprobe_busy = { static struct kprobe kprobe_busy = {
.addr = (void *) get_kprobe, .addr = (void *) get_kprobe,
}; };
...@@ -1314,7 +1312,7 @@ void kprobe_busy_end(void) ...@@ -1314,7 +1312,7 @@ void kprobe_busy_end(void)
void kprobe_flush_task(struct task_struct *tk) void kprobe_flush_task(struct task_struct *tk)
{ {
struct kretprobe_instance *ri; struct kretprobe_instance *ri;
struct hlist_head *head, empty_rp; struct hlist_head *head;
struct hlist_node *tmp; struct hlist_node *tmp;
unsigned long hash, flags = 0; unsigned long hash, flags = 0;
...@@ -1324,19 +1322,14 @@ void kprobe_flush_task(struct task_struct *tk) ...@@ -1324,19 +1322,14 @@ void kprobe_flush_task(struct task_struct *tk)
kprobe_busy_begin(); kprobe_busy_begin();
INIT_HLIST_HEAD(&empty_rp);
hash = hash_ptr(tk, KPROBE_HASH_BITS); hash = hash_ptr(tk, KPROBE_HASH_BITS);
head = &kretprobe_inst_table[hash]; head = &kretprobe_inst_table[hash];
kretprobe_table_lock(hash, &flags); kretprobe_table_lock(hash, &flags);
hlist_for_each_entry_safe(ri, tmp, head, hlist) { hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task == tk) if (ri->task == tk)
recycle_rp_inst(ri, &empty_rp); recycle_rp_inst(ri);
} }
kretprobe_table_unlock(hash, &flags); kretprobe_table_unlock(hash, &flags);
hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
hlist_del(&ri->hlist);
kfree(ri);
}
kprobe_busy_end(); kprobe_busy_end();
} }
...@@ -1360,7 +1353,8 @@ static void cleanup_rp_inst(struct kretprobe *rp) ...@@ -1360,7 +1353,8 @@ static void cleanup_rp_inst(struct kretprobe *rp)
struct hlist_node *next; struct hlist_node *next;
struct hlist_head *head; struct hlist_head *head;
/* No race here */ /* To avoid recursive kretprobe by NMI, set kprobe busy here */
kprobe_busy_begin();
for (hash = 0; hash < KPROBE_TABLE_SIZE; hash++) { for (hash = 0; hash < KPROBE_TABLE_SIZE; hash++) {
kretprobe_table_lock(hash, &flags); kretprobe_table_lock(hash, &flags);
head = &kretprobe_inst_table[hash]; head = &kretprobe_inst_table[hash];
...@@ -1370,6 +1364,8 @@ static void cleanup_rp_inst(struct kretprobe *rp) ...@@ -1370,6 +1364,8 @@ static void cleanup_rp_inst(struct kretprobe *rp)
} }
kretprobe_table_unlock(hash, &flags); kretprobe_table_unlock(hash, &flags);
} }
kprobe_busy_end();
free_rp_inst(rp); free_rp_inst(rp);
} }
NOKPROBE_SYMBOL(cleanup_rp_inst); NOKPROBE_SYMBOL(cleanup_rp_inst);
...@@ -1929,6 +1925,97 @@ unsigned long __weak arch_deref_entry_point(void *entry) ...@@ -1929,6 +1925,97 @@ unsigned long __weak arch_deref_entry_point(void *entry)
} }
#ifdef CONFIG_KRETPROBES #ifdef CONFIG_KRETPROBES
unsigned long __kretprobe_trampoline_handler(struct pt_regs *regs,
void *trampoline_address,
void *frame_pointer)
{
struct kretprobe_instance *ri = NULL, *last = NULL;
struct hlist_head *head;
struct hlist_node *tmp;
unsigned long flags;
kprobe_opcode_t *correct_ret_addr = NULL;
bool skipped = false;
kretprobe_hash_lock(current, &head, &flags);
/*
* It is possible to have multiple instances associated with a given
* task either because multiple functions in the call path have
* return probes installed on them, and/or more than one
* return probe was registered for a target function.
*
* We can handle this because:
* - instances are always pushed into the head of the list
* - when multiple return probes are registered for the same
* function, the (chronologically) first instance's ret_addr
* will be the real return address, and all the rest will
* point to kretprobe_trampoline.
*/
hlist_for_each_entry(ri, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
/*
* Return probes must be pushed on this hash list correct
* order (same as return order) so that it can be popped
* correctly. However, if we find it is pushed it incorrect
* order, this means we find a function which should not be
* probed, because the wrong order entry is pushed on the
* path of processing other kretprobe itself.
*/
if (ri->fp != frame_pointer) {
if (!skipped)
pr_warn("kretprobe is stacked incorrectly. Trying to fixup.\n");
skipped = true;
continue;
}
correct_ret_addr = ri->ret_addr;
if (skipped)
pr_warn("%ps must be blacklisted because of incorrect kretprobe order\n",
ri->rp->kp.addr);
if (correct_ret_addr != trampoline_address)
/*
* This is the real return address. Any other
* instances associated with this task are for
* other calls deeper on the call stack
*/
break;
}
BUG_ON(!correct_ret_addr || (correct_ret_addr == trampoline_address));
last = ri;
hlist_for_each_entry_safe(ri, tmp, head, hlist) {
if (ri->task != current)
/* another task is sharing our hash bucket */
continue;
if (ri->fp != frame_pointer)
continue;
if (ri->rp && ri->rp->handler) {
struct kprobe *prev = kprobe_running();
__this_cpu_write(current_kprobe, &ri->rp->kp);
ri->ret_addr = correct_ret_addr;
ri->rp->handler(ri, regs);
__this_cpu_write(current_kprobe, prev);
}
recycle_rp_inst(ri);
if (ri == last)
break;
}
kretprobe_hash_unlock(current, &flags);
return (unsigned long)correct_ret_addr;
}
NOKPROBE_SYMBOL(__kretprobe_trampoline_handler)
/* /*
* This kprobe pre_handler is registered with every kretprobe. When probe * This kprobe pre_handler is registered with every kretprobe. When probe
* hits it will set up the return probe. * hits it will set up the return probe.
...@@ -1939,17 +2026,6 @@ static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs) ...@@ -1939,17 +2026,6 @@ static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs)
unsigned long hash, flags = 0; unsigned long hash, flags = 0;
struct kretprobe_instance *ri; struct kretprobe_instance *ri;
/*
* To avoid deadlocks, prohibit return probing in NMI contexts,
* just skip the probe and increase the (inexact) 'nmissed'
* statistical counter, so that the user is informed that
* something happened:
*/
if (unlikely(in_nmi())) {
rp->nmissed++;
return 0;
}
/* TODO: consider to only swap the RA after the last pre_handler fired */ /* TODO: consider to only swap the RA after the last pre_handler fired */
hash = hash_ptr(current, KPROBE_HASH_BITS); hash = hash_ptr(current, KPROBE_HASH_BITS);
raw_spin_lock_irqsave(&rp->lock, flags); raw_spin_lock_irqsave(&rp->lock, flags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment