[3.16] tracing/uprobes: Fixes
Subsystems (3)
Steven Rostedt
maintainercover [3.16] tracing/uprobes: Fixes
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git
for-next
Head SHA1: fb6bab6a5ad46d00b5ffa22268f21df1cd7c59df
Oleg Nesterov (4):
tracing/uprobes: Revert "Support mix of ftrace and perf"
uprobes: Change unregister/apply to WARN() if uprobe/consumer is gone tracing/uprobes: Kill the bogus UPROBE_HANDLER_REMOVE code in uprobe_dispatcher() tracing/uprobes: Fix the usage of uprobe_buffer_enable() in probe_event_enable()
----
kernel/events/uprobes.c | 6 +++--- kernel/trace/trace_uprobe.c | 46 ++++++++++++++++++++++++++------------------- 2 files changed, 30 insertions(+), 22 deletions(-)
Steven Rostedt
maintainerPATCH 1/4 tracing/uprobes: Revert "Support mix of ftrace and perf"
From: Oleg Nesterov <[email protected]>
This reverts commit 43fe98913c9f67e3b523615ee3316f9520a623e0.
This patch is very wrong. Firstly, this change leads to unbalanced uprobe_unregister(). Just for example,
# perf probe -x /lib/libc.so.6 syscall # echo 1 >> /sys/kernel/debug/tracing/events/probe_libc/enable # perf record -e probe_libc:syscall whatever
after that uprobe is dead (unregistered) but the user of ftrace/perf can't know this, and it looks as if nobody hits this probe.
This would be easy to fix, but there are other reasons why it is not simple to mix ftrace and perf. If nothing else, they can't share the same ->consumer.filter. This is fixable too, but probably we need to fix the poorly designed uprobe_register() interface first. At least "register" and "apply" should be clearly separated.
--- kernel/trace/trace_uprobe.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
kernel/trace/trace_uprobe.c +8 -1
@@ -893,6 +893,9 @@ probe_event_enable(struct trace_uprobe *tu, struct ftrace_event_file *file,int ret;if (file) { +if (tu->tp.flags &TP_FLAG_PROFILE ) +return -EINTR ; + link =kmalloc (sizeof (*link),GFP_KERNEL );if (!link)return -ENOMEM ;
@@ -901,8 +904,12 @@ probe_event_enable(struct trace_uprobe *tu, struct ftrace_event_file *file,list_add_tail_rcu (&link->list, &tu->tp.files); tu->tp.flags |=TP_FLAG_TRACE ; - }else + }else { +if (tu->tp.flags &TP_FLAG_TRACE ) +return -EINTR ; + tu->tp.flags |=TP_FLAG_PROFILE ; + } ret =uprobe_buffer_enable ();if (ret <0 )
Signature · 1 line
2.0.0
Steven Rostedt
maintainerPATCH 2/4 uprobes: Change unregister/apply to WARN() if uprobe/consumer is gone
In reply to Steven RostedtFrom: Oleg Nesterov <[email protected]>
Add WARN_ON's into uprobe_unregister() and uprobe_apply() to ensure that nobody tries to play with the dead uprobe/consumer. This helps to catch the bugs like the one fixed by the previous patch.
In the longer term we should fix this poorly designed interface. uprobe_register() should return "struct uprobe *" which should be passed to apply/unregister. Plus other semantic changes, see the changelog in commit 41ccba029e94.
--- kernel/events/uprobes.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
kernel/events/uprobes.c +3 -3
@@ -846,7 +846,7 @@ static void __uprobe_unregister(struct uprobe *uprobe, struct uprobe_consumer *u {int err; -if (!consumer_del (uprobe, uc))/* WARN? */ +if (WARN_ON (!consumer_del (uprobe, uc)))return ; err =register_for_each_vma (uprobe,NULL );
@@ -927,7 +927,7 @@ int uprobe_apply(struct inode *inode, loff_t offset,int ret = -ENOENT ; uprobe =find_uprobe (inode, offset); -if (!uprobe) +if (WARN_ON (!uprobe))return ret;down_write (&uprobe->register_rwsem);
@@ -952,7 +952,7 @@ void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumestruct uprobe *uprobe; uprobe =find_uprobe (inode, offset); -if (!uprobe) +if (WARN_ON (!uprobe))return ;down_write (&uprobe->register_rwsem);
Signature · 1 line
2.0.0
Steven Rostedt
maintainerPATCH 3/4 tracing/uprobes: Kill the bogus UPROBE_HANDLER_REMOVE code in uprobe_dispatcher()
In reply to Steven RostedtFrom: Oleg Nesterov <[email protected]>
I do not know why dd9fa555d7bb "tracing/uprobes: Move argument fetching to uprobe_dispatcher()" added the UPROBE_HANDLER_REMOVE, but it looks wrong.
OK, perhaps it makes sense to avoid store_trace_args() if the tracee is nacked by uprobe_perf_filter(). But then we should kill the same code in uprobe_perf_func() and unify the TRACE/PROFILE filtering (we need to do this anyway to mix perf/ftrace). Until then this code actually adds the pessimization because uprobe_perf_filter() will be called twice and return T in likely case.
--- kernel/trace/trace_uprobe.c | 6 ------ 1 file changed, 6 deletions(-)
kernel/trace/trace_uprobe.c +0 -6
@@ -1208,12 +1208,6 @@ static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs) current->utask->vaddr = (unsigned long ) &udd; -#ifdef CONFIG_PERF_EVENTS -if ((tu->tp.flags &TP_FLAG_TRACE ) ==0 && - !uprobe_perf_filter (&tu->consumer,0 , current->mm)) -return UPROBE_HANDLER_REMOVE ; -#endif -if (WARN_ON_ONCE (!uprobe_cpu_buffer))return 0 ;
Signature · 1 line
2.0.0
Steven Rostedt
maintainerPATCH 4/4 tracing/uprobes: Fix the usage of uprobe_buffer_enable() in probe_event_enable()
In reply to Steven RostedtFrom: Oleg Nesterov <[email protected]>
The usage of uprobe_buffer_enable() added by dcad1a20 is very wrong,
1. uprobe_buffer_enable() and uprobe_buffer_disable() are not balanced, _enable() should be called only if !enabled.
2. If uprobe_buffer_enable() fails probe_event_enable() should clear tp.flags and free event_file_link.
3. If uprobe_register() fails it should do uprobe_buffer_disable().
--- kernel/trace/trace_uprobe.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-)
kernel/trace/trace_uprobe.c +19 -12
@@ -911,26 +911,33 @@ probe_event_enable(struct trace_uprobe *tu, struct ftrace_event_file *file, tu->tp.flags |=TP_FLAG_PROFILE ; } - ret =uprobe_buffer_enable (); -if (ret <0 ) -return ret; -WARN_ON (!uprobe_filter_is_empty (&tu->filter));if (enabled)return 0 ; + ret =uprobe_buffer_enable (); +if (ret) + goto err_flags; + tu->consumer.filter = filter; ret =uprobe_register (tu->inode, tu->offset, &tu->consumer); -if (ret) { -if (file) { -list_del (&link->list); -kfree (link); - tu->tp.flags &= ~TP_FLAG_TRACE ; - }else - tu->tp.flags &= ~TP_FLAG_PROFILE ; - } +if (ret) + goto err_buffer; +return 0 ; + + err_buffer: +uprobe_buffer_disable (); + + err_flags: +if (file) { +list_del (&link->list); +kfree (link); + tu->tp.flags &= ~TP_FLAG_TRACE ; + }else { + tu->tp.flags &= ~TP_FLAG_PROFILE ; + }return ret; }
Signature · 1 line
2.0.0