diff options
Diffstat (limited to 'kernel/kprobes.c')
-rw-r--r-- | kernel/kprobes.c | 34 |
1 files changed, 21 insertions, 13 deletions
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index ec4210c6501e..9737a76e106f 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
@@ -74,7 +74,8 @@ static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; | |||
74 | /* NOTE: change this value only with kprobe_mutex held */ | 74 | /* NOTE: change this value only with kprobe_mutex held */ |
75 | static bool kprobes_all_disarmed; | 75 | static bool kprobes_all_disarmed; |
76 | 76 | ||
77 | static DEFINE_MUTEX(kprobe_mutex); /* Protects kprobe_table */ | 77 | /* This protects kprobe_table and optimizing_list */ |
78 | static DEFINE_MUTEX(kprobe_mutex); | ||
78 | static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL; | 79 | static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL; |
79 | static struct { | 80 | static struct { |
80 | spinlock_t lock ____cacheline_aligned_in_smp; | 81 | spinlock_t lock ____cacheline_aligned_in_smp; |
@@ -595,6 +596,7 @@ static __kprobes void try_to_optimize_kprobe(struct kprobe *p) | |||
595 | } | 596 | } |
596 | 597 | ||
597 | #ifdef CONFIG_SYSCTL | 598 | #ifdef CONFIG_SYSCTL |
599 | /* This should be called with kprobe_mutex locked */ | ||
598 | static void __kprobes optimize_all_kprobes(void) | 600 | static void __kprobes optimize_all_kprobes(void) |
599 | { | 601 | { |
600 | struct hlist_head *head; | 602 | struct hlist_head *head; |
@@ -607,17 +609,16 @@ static void __kprobes optimize_all_kprobes(void) | |||
607 | return; | 609 | return; |
608 | 610 | ||
609 | kprobes_allow_optimization = true; | 611 | kprobes_allow_optimization = true; |
610 | mutex_lock(&text_mutex); | ||
611 | for (i = 0; i < KPROBE_TABLE_SIZE; i++) { | 612 | for (i = 0; i < KPROBE_TABLE_SIZE; i++) { |
612 | head = &kprobe_table[i]; | 613 | head = &kprobe_table[i]; |
613 | hlist_for_each_entry_rcu(p, node, head, hlist) | 614 | hlist_for_each_entry_rcu(p, node, head, hlist) |
614 | if (!kprobe_disabled(p)) | 615 | if (!kprobe_disabled(p)) |
615 | optimize_kprobe(p); | 616 | optimize_kprobe(p); |
616 | } | 617 | } |
617 | mutex_unlock(&text_mutex); | ||
618 | printk(KERN_INFO "Kprobes globally optimized\n"); | 618 | printk(KERN_INFO "Kprobes globally optimized\n"); |
619 | } | 619 | } |
620 | 620 | ||
621 | /* This should be called with kprobe_mutex locked */ | ||
621 | static void __kprobes unoptimize_all_kprobes(void) | 622 | static void __kprobes unoptimize_all_kprobes(void) |
622 | { | 623 | { |
623 | struct hlist_head *head; | 624 | struct hlist_head *head; |
@@ -1144,14 +1145,13 @@ int __kprobes register_kprobe(struct kprobe *p) | |||
1144 | if (ret) | 1145 | if (ret) |
1145 | return ret; | 1146 | return ret; |
1146 | 1147 | ||
1148 | jump_label_lock(); | ||
1147 | preempt_disable(); | 1149 | preempt_disable(); |
1148 | if (!kernel_text_address((unsigned long) p->addr) || | 1150 | if (!kernel_text_address((unsigned long) p->addr) || |
1149 | in_kprobes_functions((unsigned long) p->addr) || | 1151 | in_kprobes_functions((unsigned long) p->addr) || |
1150 | ftrace_text_reserved(p->addr, p->addr) || | 1152 | ftrace_text_reserved(p->addr, p->addr) || |
1151 | jump_label_text_reserved(p->addr, p->addr)) { | 1153 | jump_label_text_reserved(p->addr, p->addr)) |
1152 | preempt_enable(); | 1154 | goto fail_with_jump_label; |
1153 | return -EINVAL; | ||
1154 | } | ||
1155 | 1155 | ||
1156 | /* User can pass only KPROBE_FLAG_DISABLED to register_kprobe */ | 1156 | /* User can pass only KPROBE_FLAG_DISABLED to register_kprobe */ |
1157 | p->flags &= KPROBE_FLAG_DISABLED; | 1157 | p->flags &= KPROBE_FLAG_DISABLED; |
@@ -1165,10 +1165,9 @@ int __kprobes register_kprobe(struct kprobe *p) | |||
1165 | * We must hold a refcount of the probed module while updating | 1165 | * We must hold a refcount of the probed module while updating |
1166 | * its code to prohibit unexpected unloading. | 1166 | * its code to prohibit unexpected unloading. |
1167 | */ | 1167 | */ |
1168 | if (unlikely(!try_module_get(probed_mod))) { | 1168 | if (unlikely(!try_module_get(probed_mod))) |
1169 | preempt_enable(); | 1169 | goto fail_with_jump_label; |
1170 | return -EINVAL; | 1170 | |
1171 | } | ||
1172 | /* | 1171 | /* |
1173 | * If the module freed .init.text, we couldn't insert | 1172 | * If the module freed .init.text, we couldn't insert |
1174 | * kprobes in there. | 1173 | * kprobes in there. |
@@ -1176,16 +1175,18 @@ int __kprobes register_kprobe(struct kprobe *p) | |||
1176 | if (within_module_init((unsigned long)p->addr, probed_mod) && | 1175 | if (within_module_init((unsigned long)p->addr, probed_mod) && |
1177 | probed_mod->state != MODULE_STATE_COMING) { | 1176 | probed_mod->state != MODULE_STATE_COMING) { |
1178 | module_put(probed_mod); | 1177 | module_put(probed_mod); |
1179 | preempt_enable(); | 1178 | goto fail_with_jump_label; |
1180 | return -EINVAL; | ||
1181 | } | 1179 | } |
1182 | } | 1180 | } |
1183 | preempt_enable(); | 1181 | preempt_enable(); |
1182 | jump_label_unlock(); | ||
1184 | 1183 | ||
1185 | p->nmissed = 0; | 1184 | p->nmissed = 0; |
1186 | INIT_LIST_HEAD(&p->list); | 1185 | INIT_LIST_HEAD(&p->list); |
1187 | mutex_lock(&kprobe_mutex); | 1186 | mutex_lock(&kprobe_mutex); |
1188 | 1187 | ||
1188 | jump_label_lock(); /* needed to call jump_label_text_reserved() */ | ||
1189 | |||
1189 | get_online_cpus(); /* For avoiding text_mutex deadlock. */ | 1190 | get_online_cpus(); /* For avoiding text_mutex deadlock. */ |
1190 | mutex_lock(&text_mutex); | 1191 | mutex_lock(&text_mutex); |
1191 | 1192 | ||
@@ -1213,12 +1214,18 @@ int __kprobes register_kprobe(struct kprobe *p) | |||
1213 | out: | 1214 | out: |
1214 | mutex_unlock(&text_mutex); | 1215 | mutex_unlock(&text_mutex); |
1215 | put_online_cpus(); | 1216 | put_online_cpus(); |
1217 | jump_label_unlock(); | ||
1216 | mutex_unlock(&kprobe_mutex); | 1218 | mutex_unlock(&kprobe_mutex); |
1217 | 1219 | ||
1218 | if (probed_mod) | 1220 | if (probed_mod) |
1219 | module_put(probed_mod); | 1221 | module_put(probed_mod); |
1220 | 1222 | ||
1221 | return ret; | 1223 | return ret; |
1224 | |||
1225 | fail_with_jump_label: | ||
1226 | preempt_enable(); | ||
1227 | jump_label_unlock(); | ||
1228 | return -EINVAL; | ||
1222 | } | 1229 | } |
1223 | EXPORT_SYMBOL_GPL(register_kprobe); | 1230 | EXPORT_SYMBOL_GPL(register_kprobe); |
1224 | 1231 | ||
@@ -2000,6 +2007,7 @@ static ssize_t write_enabled_file_bool(struct file *file, | |||
2000 | static const struct file_operations fops_kp = { | 2007 | static const struct file_operations fops_kp = { |
2001 | .read = read_enabled_file_bool, | 2008 | .read = read_enabled_file_bool, |
2002 | .write = write_enabled_file_bool, | 2009 | .write = write_enabled_file_bool, |
2010 | .llseek = default_llseek, | ||
2003 | }; | 2011 | }; |
2004 | 2012 | ||
2005 | static int __kprobes debugfs_kprobe_init(void) | 2013 | static int __kprobes debugfs_kprobe_init(void) |