Commit 5c51543b authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Linus Torvalds

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 ad72b3be ("kprobes: fix
wait_for_kprobe_optimizer()")
Signed-off-by: default avatarMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Acked-by: default avatarAnanth 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: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent d202f051
...@@ -794,16 +794,16 @@ static __kprobes void try_to_optimize_kprobe(struct kprobe *p) ...@@ -794,16 +794,16 @@ static __kprobes void try_to_optimize_kprobe(struct kprobe *p)
} }
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
/* This should be called with kprobe_mutex locked */
static void __kprobes optimize_all_kprobes(void) static void __kprobes optimize_all_kprobes(void)
{ {
struct hlist_head *head; struct hlist_head *head;
struct kprobe *p; struct kprobe *p;
unsigned int i; unsigned int i;
mutex_lock(&kprobe_mutex);
/* If optimization is already allowed, just return */ /* If optimization is already allowed, just return */
if (kprobes_allow_optimization) if (kprobes_allow_optimization)
return; goto out;
kprobes_allow_optimization = true; kprobes_allow_optimization = true;
for (i = 0; i < KPROBE_TABLE_SIZE; i++) { for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
...@@ -813,18 +813,22 @@ static void __kprobes optimize_all_kprobes(void) ...@@ -813,18 +813,22 @@ static void __kprobes optimize_all_kprobes(void)
optimize_kprobe(p); optimize_kprobe(p);
} }
printk(KERN_INFO "Kprobes globally optimized\n"); 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) static void __kprobes unoptimize_all_kprobes(void)
{ {
struct hlist_head *head; struct hlist_head *head;
struct kprobe *p; struct kprobe *p;
unsigned int i; unsigned int i;
mutex_lock(&kprobe_mutex);
/* If optimization is already prohibited, just return */ /* If optimization is already prohibited, just return */
if (!kprobes_allow_optimization) if (!kprobes_allow_optimization) {
mutex_unlock(&kprobe_mutex);
return; return;
}
kprobes_allow_optimization = false; kprobes_allow_optimization = false;
for (i = 0; i < KPROBE_TABLE_SIZE; i++) { for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
...@@ -834,11 +838,14 @@ static void __kprobes unoptimize_all_kprobes(void) ...@@ -834,11 +838,14 @@ static void __kprobes unoptimize_all_kprobes(void)
unoptimize_kprobe(p, false); unoptimize_kprobe(p, false);
} }
} }
mutex_unlock(&kprobe_mutex);
/* Wait for unoptimizing completion */ /* Wait for unoptimizing completion */
wait_for_kprobe_optimizer(); wait_for_kprobe_optimizer();
printk(KERN_INFO "Kprobes globally unoptimized\n"); printk(KERN_INFO "Kprobes globally unoptimized\n");
} }
static DEFINE_MUTEX(kprobe_sysctl_mutex);
int sysctl_kprobes_optimization; int sysctl_kprobes_optimization;
int proc_kprobes_optimization_handler(struct ctl_table *table, int write, int proc_kprobes_optimization_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *length, void __user *buffer, size_t *length,
...@@ -846,7 +853,7 @@ int proc_kprobes_optimization_handler(struct ctl_table *table, int write, ...@@ -846,7 +853,7 @@ int proc_kprobes_optimization_handler(struct ctl_table *table, int write,
{ {
int ret; int ret;
mutex_lock(&kprobe_mutex); mutex_lock(&kprobe_sysctl_mutex);
sysctl_kprobes_optimization = kprobes_allow_optimization ? 1 : 0; sysctl_kprobes_optimization = kprobes_allow_optimization ? 1 : 0;
ret = proc_dointvec_minmax(table, write, buffer, length, ppos); ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
...@@ -854,7 +861,7 @@ int proc_kprobes_optimization_handler(struct ctl_table *table, int write, ...@@ -854,7 +861,7 @@ int proc_kprobes_optimization_handler(struct ctl_table *table, int write,
optimize_all_kprobes(); optimize_all_kprobes();
else else
unoptimize_all_kprobes(); unoptimize_all_kprobes();
mutex_unlock(&kprobe_mutex); mutex_unlock(&kprobe_sysctl_mutex);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment