Commit 3f74306a authored by Rob Gardner's avatar Rob Gardner Committed by David S. Miller

sparc64: Ensure perf can access user stacks

When an interrupt (such as a perf counter interrupt) is delivered
while executing in user space, the trap entry code puts ASI_AIUS in
%asi so that copy_from_user() and copy_to_user() will access the
correct memory. But if a perf counter interrupt is delivered while the
cpu is already executing in kernel space, then the trap entry code
will put ASI_P in %asi, and this will prevent copy_from_user() from
reading any useful stack data in either of the perf_callchain_user_X
functions, and thus no user callgraph data will be collected for this
sample period. An additional problem is that a fault is guaranteed
to occur, and though it will be silently covered up, it wastes time
and could perturb state.

In perf_callchain_user(), we ensure that %asi contains ASI_AIUS
because we know for a fact that the subsequent calls to
copy_from_user() are intended to read the user's stack.

[ Use get_fs()/set_fs() -DaveM ]
Signed-off-by: default avatarRob Gardner <rob.gardner@oracle.com>
Signed-off-by: default avatarDave Aldridge <david.j.aldridge@oracle.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1ca04a4c
...@@ -1828,11 +1828,16 @@ static void perf_callchain_user_32(struct perf_callchain_entry *entry, ...@@ -1828,11 +1828,16 @@ static void perf_callchain_user_32(struct perf_callchain_entry *entry,
void void
perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
{ {
mm_segment_t old_fs;
perf_callchain_store(entry, regs->tpc); perf_callchain_store(entry, regs->tpc);
if (!current->mm) if (!current->mm)
return; return;
old_fs = get_fs();
set_fs(USER_DS);
flushw_user(); flushw_user();
pagefault_disable(); pagefault_disable();
...@@ -1843,4 +1848,6 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) ...@@ -1843,4 +1848,6 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
perf_callchain_user_64(entry, regs); perf_callchain_user_64(entry, regs);
pagefault_enable(); pagefault_enable();
set_fs(old_fs);
} }
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