Commit 20955746 authored by Vasily Gorbik's avatar Vasily Gorbik

s390/kasan: avoid false positives during stack unwind

Avoid kasan false positive when current task is interrupted in-between
stack frame allocation and backchain write instructions leaving new stack
frame backchain invalid. In particular if backchain is 0 the unwinder
tries to read pt_regs from the stack and might hit kasan poisoned bytes,
leading to kasan "stack-out-of-bounds" report.

Disable kasan instrumentation of unwinder stack reads, since this
limitation couldn't be handled otherwise with current backchain unwinder
implementation.

Fixes: 78c98f90 ("s390/unwind: introduce stack unwind API")
Reported-by: default avatarJulian Wiedmann <jwi@linux.ibm.com>
Tested-by: default avatarBenjamin Block <bblock@linux.ibm.com>
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent ac6639cd
...@@ -46,18 +46,18 @@ bool unwind_next_frame(struct unwind_state *state) ...@@ -46,18 +46,18 @@ bool unwind_next_frame(struct unwind_state *state)
regs = state->regs; regs = state->regs;
if (unlikely(regs)) { if (unlikely(regs)) {
sp = READ_ONCE_TASK_STACK(state->task, regs->gprs[15]); sp = READ_ONCE_NOCHECK(regs->gprs[15]);
if (unlikely(outside_of_stack(state, sp))) { if (unlikely(outside_of_stack(state, sp))) {
if (!update_stack_info(state, sp)) if (!update_stack_info(state, sp))
goto out_err; goto out_err;
} }
sf = (struct stack_frame *) sp; sf = (struct stack_frame *) sp;
ip = READ_ONCE_TASK_STACK(state->task, sf->gprs[8]); ip = READ_ONCE_NOCHECK(sf->gprs[8]);
reliable = false; reliable = false;
regs = NULL; regs = NULL;
} else { } else {
sf = (struct stack_frame *) state->sp; sf = (struct stack_frame *) state->sp;
sp = READ_ONCE_TASK_STACK(state->task, sf->back_chain); sp = READ_ONCE_NOCHECK(sf->back_chain);
if (likely(sp)) { if (likely(sp)) {
/* Non-zero back-chain points to the previous frame */ /* Non-zero back-chain points to the previous frame */
if (unlikely(outside_of_stack(state, sp))) { if (unlikely(outside_of_stack(state, sp))) {
...@@ -65,7 +65,7 @@ bool unwind_next_frame(struct unwind_state *state) ...@@ -65,7 +65,7 @@ bool unwind_next_frame(struct unwind_state *state)
goto out_err; goto out_err;
} }
sf = (struct stack_frame *) sp; sf = (struct stack_frame *) sp;
ip = READ_ONCE_TASK_STACK(state->task, sf->gprs[8]); ip = READ_ONCE_NOCHECK(sf->gprs[8]);
reliable = true; reliable = true;
} else { } else {
/* No back-chain, look for a pt_regs structure */ /* No back-chain, look for a pt_regs structure */
...@@ -73,9 +73,9 @@ bool unwind_next_frame(struct unwind_state *state) ...@@ -73,9 +73,9 @@ bool unwind_next_frame(struct unwind_state *state)
if (!on_stack(info, sp, sizeof(struct pt_regs))) if (!on_stack(info, sp, sizeof(struct pt_regs)))
goto out_stop; goto out_stop;
regs = (struct pt_regs *) sp; regs = (struct pt_regs *) sp;
if (user_mode(regs)) if (READ_ONCE_NOCHECK(regs->psw.mask) & PSW_MASK_PSTATE)
goto out_stop; goto out_stop;
ip = READ_ONCE_TASK_STACK(state->task, regs->psw.addr); ip = READ_ONCE_NOCHECK(regs->psw.addr);
reliable = true; reliable = true;
} }
} }
...@@ -132,11 +132,11 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task, ...@@ -132,11 +132,11 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task,
/* Get the instruction pointer from pt_regs or the stack frame */ /* Get the instruction pointer from pt_regs or the stack frame */
if (regs) { if (regs) {
ip = READ_ONCE_TASK_STACK(state->task, regs->psw.addr); ip = READ_ONCE_NOCHECK(regs->psw.addr);
reliable = true; reliable = true;
} else { } else {
sf = (struct stack_frame *) sp; sf = (struct stack_frame *) sp;
ip = READ_ONCE_TASK_STACK(state->task, sf->gprs[8]); ip = READ_ONCE_NOCHECK(sf->gprs[8]);
reliable = false; reliable = false;
} }
......
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