Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 20955746 authored by Vasily Gorbik's avatar Vasily Gorbik
Browse files

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
Loading
Loading
Loading
Loading
+8 −8
Original line number Diff line number Diff line
@@ -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;
	}