diff mbox

[2/2] sparc64: Perf should save/restore fault info

Message ID 1450844167-7327-2-git-send-email-rob.gardner@oracle.com
State Accepted
Delegated to: David Miller
Headers show

Commit Message

Rob Gardner Dec. 23, 2015, 4:16 a.m. UTC
There have been several reports of random processes being killed with
a bus error or segfault during userspace stack walking in perf.  One
of the root causes of this problem is an asynchronous modification to
thread_info fault_address and fault_code, which stems from a perf
counter interrupt arriving during kernel processing of a "benign"
fault, such as a TSB miss. Since perf_callchain_user() invokes
copy_from_user() to read user stacks, a fault is not only possible,
but probable. Validity checks on the stack address merely cover up the
problem and reduce its frequency.

The solution here is to save and restore fault_address and fault_code
in perf_callchain_user() so that the benign fault handler is not
disturbed by a perf interrupt.

Signed-off-by: Rob Gardner <rob.gardner@oracle.com>
Signed-off-by: Dave Aldridge <david.j.aldridge@oracle.com>
---
 arch/sparc/kernel/perf_event.c |    4 ++++
 1 file changed, 4 insertions(+)

Comments

David Miller Dec. 24, 2015, 4:43 p.m. UTC | #1
From: Rob Gardner <rob.gardner@oracle.com>
Date: Tue, 22 Dec 2015 21:16:07 -0700

> There have been several reports of random processes being killed with
> a bus error or segfault during userspace stack walking in perf.  One
> of the root causes of this problem is an asynchronous modification to
> thread_info fault_address and fault_code, which stems from a perf
> counter interrupt arriving during kernel processing of a "benign"
> fault, such as a TSB miss. Since perf_callchain_user() invokes
> copy_from_user() to read user stacks, a fault is not only possible,
> but probable. Validity checks on the stack address merely cover up the
> problem and reduce its frequency.
> 
> The solution here is to save and restore fault_address and fault_code
> in perf_callchain_user() so that the benign fault handler is not
> disturbed by a perf interrupt.
> 
> Signed-off-by: Rob Gardner <rob.gardner@oracle.com>
> Signed-off-by: Dave Aldridge <david.j.aldridge@oracle.com>

Applied.
--
To unsubscribe from this list: send the line "unsubscribe sparclinux" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c
index 55a6caa..cb20d34 100644
--- a/arch/sparc/kernel/perf_event.c
+++ b/arch/sparc/kernel/perf_event.c
@@ -1810,6 +1810,8 @@  static void perf_callchain_user_32(struct perf_callchain_entry *entry,
 void
 perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
 {
+	u64 saved_fault_address = current_thread_info()->fault_address;
+	u8  saved_fault_code = get_thread_fault_code();
 	u8  saved_asi;
 
 	perf_callchain_store(entry, regs->tpc);
@@ -1837,4 +1839,6 @@  perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
 	if (saved_asi != ASI_AIUS)
 		__asm__ __volatile__ (
 			"wr %%g0, %0, %%asi\n" : : "r" (saved_asi));
+	set_thread_fault_code(saved_fault_code);
+	current_thread_info()->fault_address = saved_fault_address;
 }