This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
[patch added to 3.12-stable] kprobes/x86: Clear TF bit in fault on single-stepping
- From: Jiri Slaby <jslaby at suse dot cz>
- To: stable at vger dot kernel dot org
- Cc: Masami Hiramatsu <mhiramat at kernel dot org>, Alexander Shishkin <alexander dot shishkin at linux dot intel dot com>, Andy Lutomirski <luto at kernel dot org>, Arnaldo Carvalho de Melo <acme at redhat dot com>, Borislav Petkov <bp at alien8 dot de>, Brian Gerst <brgerst at gmail dot com>, Denys Vlasenko <dvlasenk at redhat dot com>, "H . Peter Anvin" <hpa at zytor dot com>, Jiri Olsa <jolsa at redhat dot com>, Linus Torvalds <torvalds at linux-foundation dot org>, Peter Zijlstra <peterz at infradead dot org>, Stephane Eranian <eranian at google dot com>, Thomas Gleixner <tglx at linutronix dot de>, Vince Weaver <vincent dot weaver at maine dot edu>, systemtap at sourceware dot org, Ingo Molnar <mingo at kernel dot org>, Jiri Slaby <jslaby at suse dot cz>
- Date: Tue, 12 Jul 2016 11:41:21 +0200
- Subject: [patch added to 3.12-stable] kprobes/x86: Clear TF bit in fault on single-stepping
- Authentication-results: sourceware.org; auth=none
- References: <20160712094129.25202-1-jslaby@suse.cz>
From: Masami Hiramatsu <mhiramat@kernel.org>
This patch has been added to the 3.12 stable tree. If you have any
objections, please let us know.
===============
commit dcfc47248d3f7d28df6f531e6426b933de94370d upstream.
Fix kprobe_fault_handler() to clear the TF (trap flag) bit of
the flags register in the case of a fault fixup on single-stepping.
If we put a kprobe on the instruction which caused a
page fault (e.g. actual mov instructions in copy_user_*),
that fault happens on the single-stepping buffer. In this
case, kprobes resets running instance so that the CPU can
retry execution on the original ip address.
However, current code forgets to reset the TF bit. Since this
fault happens with TF bit set for enabling single-stepping,
when it retries, it causes a debug exception and kprobes
can not handle it because it already reset itself.
On the most of x86-64 platform, it can be easily reproduced
by using kprobe tracer. E.g.
# cd /sys/kernel/debug/tracing
# echo p copy_user_enhanced_fast_string+5 > kprobe_events
# echo 1 > events/kprobes/enable
And you'll see a kernel panic on do_debug(), since the debug
trap is not handled by kprobes.
To fix this problem, we just need to clear the TF bit when
resetting running kprobe.
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Reviewed-by: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Vince Weaver <vincent.weaver@maine.edu>
Cc: systemtap@sourceware.org
Link: http://lkml.kernel.org/r/20160611140648.25885.37482.stgit@devbox
[ Updated the comments. ]
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
---
arch/x86/kernel/kprobes/core.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c
index 490fee15fea5..6cd32acb376f 100644
--- a/arch/x86/kernel/kprobes/core.c
+++ b/arch/x86/kernel/kprobes/core.c
@@ -911,7 +911,19 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
* normal page fault.
*/
regs->ip = (unsigned long)cur->addr;
+ /*
+ * Trap flag (TF) has been set here because this fault
+ * happened where the single stepping will be done.
+ * So clear it by resetting the current kprobe:
+ */
+ regs->flags &= ~X86_EFLAGS_TF;
+
+ /*
+ * If the TF flag was set before the kprobe hit,
+ * don't touch it:
+ */
regs->flags |= kcb->kprobe_old_flags;
+
if (kcb->kprobe_status == KPROBE_REENTER)
restore_previous_kprobe(kcb);
else
--
2.9.0