Skip to content

Commit

Permalink
kprobes: cleanup to separate probe-able check
Browse files Browse the repository at this point in the history
Separate probe-able address checking code from
register_kprobe().

Link: http://lkml.kernel.org/r/[email protected]

Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>
Cc: Ananth N Mavinakayanahalli <[email protected]>
Cc: "Frank Ch. Eigler" <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Signed-off-by: Masami Hiramatsu <[email protected]>
Signed-off-by: Steven Rostedt <[email protected]>
  • Loading branch information
mhiramathitachi authored and rostedt committed Jul 31, 2012
1 parent 72ef379 commit f7fa6ef
Showing 1 changed file with 45 additions and 37 deletions.
82 changes: 45 additions & 37 deletions kernel/kprobes.c
Original file line number Diff line number Diff line change
Expand Up @@ -1313,67 +1313,80 @@ static inline int check_kprobe_rereg(struct kprobe *p)
return ret;
}

int __kprobes register_kprobe(struct kprobe *p)
static __kprobes int check_kprobe_address_safe(struct kprobe *p,
struct module **probed_mod)
{
int ret = 0;
struct kprobe *old_p;
struct module *probed_mod;
kprobe_opcode_t *addr;

addr = kprobe_addr(p);
if (IS_ERR(addr))
return PTR_ERR(addr);
p->addr = addr;

ret = check_kprobe_rereg(p);
if (ret)
return ret;

jump_label_lock();
preempt_disable();

/* Ensure it is not in reserved area nor out of text */
if (!kernel_text_address((unsigned long) p->addr) ||
in_kprobes_functions((unsigned long) p->addr) ||
ftrace_text_reserved(p->addr, p->addr) ||
jump_label_text_reserved(p->addr, p->addr)) {
ret = -EINVAL;
goto cannot_probe;
goto out;
}

/* User can pass only KPROBE_FLAG_DISABLED to register_kprobe */
p->flags &= KPROBE_FLAG_DISABLED;

/*
* Check if are we probing a module.
*/
probed_mod = __module_text_address((unsigned long) p->addr);
if (probed_mod) {
/* Return -ENOENT if fail. */
ret = -ENOENT;
/* Check if are we probing a module */
*probed_mod = __module_text_address((unsigned long) p->addr);
if (*probed_mod) {
/*
* We must hold a refcount of the probed module while updating
* its code to prohibit unexpected unloading.
*/
if (unlikely(!try_module_get(probed_mod)))
goto cannot_probe;
if (unlikely(!try_module_get(*probed_mod))) {
ret = -ENOENT;
goto out;
}

/*
* If the module freed .init.text, we couldn't insert
* kprobes in there.
*/
if (within_module_init((unsigned long)p->addr, probed_mod) &&
probed_mod->state != MODULE_STATE_COMING) {
module_put(probed_mod);
goto cannot_probe;
if (within_module_init((unsigned long)p->addr, *probed_mod) &&
(*probed_mod)->state != MODULE_STATE_COMING) {
module_put(*probed_mod);
*probed_mod = NULL;
ret = -ENOENT;
}
/* ret will be updated by following code */
}
out:
preempt_enable();
jump_label_unlock();

return ret;
}

int __kprobes register_kprobe(struct kprobe *p)
{
int ret;
struct kprobe *old_p;
struct module *probed_mod;
kprobe_opcode_t *addr;

/* Adjust probe address from symbol */
addr = kprobe_addr(p);
if (IS_ERR(addr))
return PTR_ERR(addr);
p->addr = addr;

ret = check_kprobe_rereg(p);
if (ret)
return ret;

/* User can pass only KPROBE_FLAG_DISABLED to register_kprobe */
p->flags &= KPROBE_FLAG_DISABLED;
p->nmissed = 0;
INIT_LIST_HEAD(&p->list);
mutex_lock(&kprobe_mutex);

ret = check_kprobe_address_safe(p, &probed_mod);
if (ret)
return ret;

mutex_lock(&kprobe_mutex);
jump_label_lock(); /* needed to call jump_label_text_reserved() */

get_online_cpus(); /* For avoiding text_mutex deadlock. */
Expand Down Expand Up @@ -1410,11 +1423,6 @@ int __kprobes register_kprobe(struct kprobe *p)
module_put(probed_mod);

return ret;

cannot_probe:
preempt_enable();
jump_label_unlock();
return ret;
}
EXPORT_SYMBOL_GPL(register_kprobe);

Expand Down

0 comments on commit f7fa6ef

Please sign in to comment.