kprobes: Fix a double lock bug of kprobe_mutex
Fix a double locking bug caused when debug.kprobe-optimization=0.
While the proc_kprobes_optimization_handler locks kprobe_mutex,
wait_for_kprobe_optimizer locks it again and that causes a double lock.
To fix the bug, this introduces different mutex for protecting
sysctl parameter and locks it in proc_kprobes_optimization_handler.
Of course, since we need to lock kprobe_mutex when touching kprobes
resources, that is done in *optimize_all_kprobes().
This bug was introduced by commit ad72b3bea7 ("kprobes: fix
wait_for_kprobe_optimizer()")
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Acked-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
			
			
This commit is contained in:
		
							parent
							
								
									d202f05158
								
							
						
					
					
						commit
						5c51543b0a
					
				| @ -794,16 +794,16 @@ out: | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_SYSCTL | ||||
| /* This should be called with kprobe_mutex locked */ | ||||
| static void __kprobes optimize_all_kprobes(void) | ||||
| { | ||||
| 	struct hlist_head *head; | ||||
| 	struct kprobe *p; | ||||
| 	unsigned int i; | ||||
| 
 | ||||
| 	mutex_lock(&kprobe_mutex); | ||||
| 	/* If optimization is already allowed, just return */ | ||||
| 	if (kprobes_allow_optimization) | ||||
| 		return; | ||||
| 		goto out; | ||||
| 
 | ||||
| 	kprobes_allow_optimization = true; | ||||
| 	for (i = 0; i < KPROBE_TABLE_SIZE; i++) { | ||||
| @ -813,18 +813,22 @@ static void __kprobes optimize_all_kprobes(void) | ||||
| 				optimize_kprobe(p); | ||||
| 	} | ||||
| 	printk(KERN_INFO "Kprobes globally optimized\n"); | ||||
| out: | ||||
| 	mutex_unlock(&kprobe_mutex); | ||||
| } | ||||
| 
 | ||||
| /* This should be called with kprobe_mutex locked */ | ||||
| static void __kprobes unoptimize_all_kprobes(void) | ||||
| { | ||||
| 	struct hlist_head *head; | ||||
| 	struct kprobe *p; | ||||
| 	unsigned int i; | ||||
| 
 | ||||
| 	mutex_lock(&kprobe_mutex); | ||||
| 	/* If optimization is already prohibited, just return */ | ||||
| 	if (!kprobes_allow_optimization) | ||||
| 	if (!kprobes_allow_optimization) { | ||||
| 		mutex_unlock(&kprobe_mutex); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	kprobes_allow_optimization = false; | ||||
| 	for (i = 0; i < KPROBE_TABLE_SIZE; i++) { | ||||
| @ -834,11 +838,14 @@ static void __kprobes unoptimize_all_kprobes(void) | ||||
| 				unoptimize_kprobe(p, false); | ||||
| 		} | ||||
| 	} | ||||
| 	mutex_unlock(&kprobe_mutex); | ||||
| 
 | ||||
| 	/* Wait for unoptimizing completion */ | ||||
| 	wait_for_kprobe_optimizer(); | ||||
| 	printk(KERN_INFO "Kprobes globally unoptimized\n"); | ||||
| } | ||||
| 
 | ||||
| static DEFINE_MUTEX(kprobe_sysctl_mutex); | ||||
| int sysctl_kprobes_optimization; | ||||
| int proc_kprobes_optimization_handler(struct ctl_table *table, int write, | ||||
| 				      void __user *buffer, size_t *length, | ||||
| @ -846,7 +853,7 @@ int proc_kprobes_optimization_handler(struct ctl_table *table, int write, | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	mutex_lock(&kprobe_mutex); | ||||
| 	mutex_lock(&kprobe_sysctl_mutex); | ||||
| 	sysctl_kprobes_optimization = kprobes_allow_optimization ? 1 : 0; | ||||
| 	ret = proc_dointvec_minmax(table, write, buffer, length, ppos); | ||||
| 
 | ||||
| @ -854,7 +861,7 @@ int proc_kprobes_optimization_handler(struct ctl_table *table, int write, | ||||
| 		optimize_all_kprobes(); | ||||
| 	else | ||||
| 		unoptimize_all_kprobes(); | ||||
| 	mutex_unlock(&kprobe_mutex); | ||||
| 	mutex_unlock(&kprobe_sysctl_mutex); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user