Commit cd581092 authored by Heiko Carstens's avatar Heiko Carstens Committed by Alexander Gordeev

s390/stacktrace: Improve detection of invalid instruction pointers

Add basic checks to identify invalid instruction pointers when walking
stack frames:

Instruction pointers must

- have even addresses
- be larger than mmap_min_addr
- lower than the asce_limit of the process

Alternatively it would also be possible to walk page tables similar to fast
GUP and verify that the mapping of the corresponding page is executable,
however that seems to be overkill.

Fixes: aa44433a ("s390: add USER_STACKTRACE support")
Reviewed-by: default avatarJens Remus <jremus@linux.ibm.com>
Signed-off-by: default avatarHeiko Carstens <hca@linux.ibm.com>
Signed-off-by: default avatarAlexander Gordeev <agordeev@linux.ibm.com>
parent 87eceb17
...@@ -77,6 +77,21 @@ static inline bool store_ip(stack_trace_consume_fn consume_entry, void *cookie, ...@@ -77,6 +77,21 @@ static inline bool store_ip(stack_trace_consume_fn consume_entry, void *cookie,
return consume_entry(cookie, ip); return consume_entry(cookie, ip);
} }
static inline bool ip_invalid(unsigned long ip)
{
/*
* Perform some basic checks if an instruction address taken
* from unreliable source is invalid.
*/
if (ip & 1)
return true;
if (ip < mmap_min_addr)
return true;
if (ip >= current->mm->context.asce_limit)
return true;
return false;
}
void arch_stack_walk_user_common(stack_trace_consume_fn consume_entry, void *cookie, void arch_stack_walk_user_common(stack_trace_consume_fn consume_entry, void *cookie,
struct perf_callchain_entry_ctx *entry, struct perf_callchain_entry_ctx *entry,
const struct pt_regs *regs, bool perf) const struct pt_regs *regs, bool perf)
...@@ -87,6 +102,8 @@ void arch_stack_walk_user_common(stack_trace_consume_fn consume_entry, void *coo ...@@ -87,6 +102,8 @@ void arch_stack_walk_user_common(stack_trace_consume_fn consume_entry, void *coo
if (is_compat_task()) if (is_compat_task())
return; return;
if (!current->mm)
return;
ip = instruction_pointer(regs); ip = instruction_pointer(regs);
if (!store_ip(consume_entry, cookie, entry, perf, ip)) if (!store_ip(consume_entry, cookie, entry, perf, ip))
return; return;
...@@ -101,15 +118,16 @@ void arch_stack_walk_user_common(stack_trace_consume_fn consume_entry, void *coo ...@@ -101,15 +118,16 @@ void arch_stack_walk_user_common(stack_trace_consume_fn consume_entry, void *coo
sf = (void __user *)sp; sf = (void __user *)sp;
if (__get_user(ip, &sf->gprs[8])) if (__get_user(ip, &sf->gprs[8]))
break; break;
if (ip & 0x1) { if (ip_invalid(ip)) {
/* /*
* If the instruction address is invalid, and this * If the instruction address is invalid, and this
* is the first stack frame, assume r14 has not * is the first stack frame, assume r14 has not
* been written to the stack yet. Otherwise exit. * been written to the stack yet. Otherwise exit.
*/ */
if (first && !(regs->gprs[14] & 0x1)) if (!first)
ip = regs->gprs[14]; break;
else ip = regs->gprs[14];
if (ip_invalid(ip))
break; break;
} }
if (!store_ip(consume_entry, cookie, entry, perf, ip)) if (!store_ip(consume_entry, cookie, entry, perf, ip))
......
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