s390/kasan: avoid false positives during stack unwind
authorVasily Gorbik <gor@linux.ibm.com>
Thu, 20 Jun 2019 08:18:31 +0000 (10:18 +0200)
committerVasily Gorbik <gor@linux.ibm.com>
Tue, 2 Jul 2019 14:00:27 +0000 (16:00 +0200)
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: 78c98f907413 ("s390/unwind: introduce stack unwind API")
Reported-by: Julian Wiedmann <jwi@linux.ibm.com>
Tested-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
arch/s390/kernel/unwind_bc.c

index 57fd4e902f1f49eaf3125c29482f0e32ab8cce23..3ce8a0808059b634c2b326a82d2e0c9237dd7173 100644 (file)
@@ -46,18 +46,18 @@ bool unwind_next_frame(struct unwind_state *state)
 
        regs = state->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 (!update_stack_info(state, sp))
                                goto out_err;
                }
                sf = (struct stack_frame *) sp;
-               ip = READ_ONCE_TASK_STACK(state->task, sf->gprs[8]);
+               ip = READ_ONCE_NOCHECK(sf->gprs[8]);
                reliable = false;
                regs = NULL;
        } else {
                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)) {
                        /* Non-zero back-chain points to the previous frame */
                        if (unlikely(outside_of_stack(state, sp))) {
@@ -65,7 +65,7 @@ bool unwind_next_frame(struct unwind_state *state)
                                        goto out_err;
                        }
                        sf = (struct stack_frame *) sp;
-                       ip = READ_ONCE_TASK_STACK(state->task, sf->gprs[8]);
+                       ip = READ_ONCE_NOCHECK(sf->gprs[8]);
                        reliable = true;
                } else {
                        /* No back-chain, look for a pt_regs structure */
@@ -73,9 +73,9 @@ bool unwind_next_frame(struct unwind_state *state)
                        if (!on_stack(info, sp, sizeof(struct pt_regs)))
                                goto out_stop;
                        regs = (struct pt_regs *) sp;
-                       if (user_mode(regs))
+                       if (READ_ONCE_NOCHECK(regs->psw.mask) & PSW_MASK_PSTATE)
                                goto out_stop;
-                       ip = READ_ONCE_TASK_STACK(state->task, regs->psw.addr);
+                       ip = READ_ONCE_NOCHECK(regs->psw.addr);
                        reliable = true;
                }
        }
@@ -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 */
        if (regs) {
-               ip = READ_ONCE_TASK_STACK(state->task, regs->psw.addr);
+               ip = READ_ONCE_NOCHECK(regs->psw.addr);
                reliable = true;
        } else {
                sf = (struct stack_frame *) sp;
-               ip = READ_ONCE_TASK_STACK(state->task, sf->gprs[8]);
+               ip = READ_ONCE_NOCHECK(sf->gprs[8]);
                reliable = false;
        }