|
@@ -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. */
|
|
@@ -1410,11 +1423,6 @@ out:
|
|
|
module_put(probed_mod);
|
|
|
|
|
|
return ret;
|
|
|
-
|
|
|
-cannot_probe:
|
|
|
- preempt_enable();
|
|
|
- jump_label_unlock();
|
|
|
- return ret;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(register_kprobe);
|
|
|
|