aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/kprobes.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kprobes.c')
-rw-r--r--kernel/kprobes.c34
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 */
75static bool kprobes_all_disarmed; 75static bool kprobes_all_disarmed;
76 76
77static DEFINE_MUTEX(kprobe_mutex); /* Protects kprobe_table */ 77/* This protects kprobe_table and optimizing_list */
78static DEFINE_MUTEX(kprobe_mutex);
78static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL; 79static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL;
79static struct { 80static 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 */
598static void __kprobes optimize_all_kprobes(void) 600static 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 */
621static void __kprobes unoptimize_all_kprobes(void) 622static 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)
1213out: 1214out:
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
1225fail_with_jump_label:
1226 preempt_enable();
1227 jump_label_unlock();
1228 return -EINVAL;
1222} 1229}
1223EXPORT_SYMBOL_GPL(register_kprobe); 1230EXPORT_SYMBOL_GPL(register_kprobe);
1224 1231
@@ -2000,6 +2007,7 @@ static ssize_t write_enabled_file_bool(struct file *file,
2000static const struct file_operations fops_kp = { 2007static 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
2005static int __kprobes debugfs_kprobe_init(void) 2013static int __kprobes debugfs_kprobe_init(void)