Skip to content

Commit aa137a6

Browse files
mirabVasily Gorbik
authored andcommitted
s390/livepatch: Implement reliable stack tracing for the consistency model
The livepatch consistency model requires reliable stack tracing architecture support in order to work properly. In order to achieve this, two main issues have to be solved. First, reliable and consistent call chain backtracing has to be ensured. Second, the unwinder needs to be able to detect stack corruptions and return errors. The "zSeries ELF Application Binary Interface Supplement" says: "The stack pointer points to the first word of the lowest allocated stack frame. If the "back chain" is implemented this word will point to the previously allocated stack frame (towards higher addresses), except for the first stack frame, which shall have a back chain of zero (NULL). The stack shall grow downwards, in other words towards lower addresses." "back chain" is optional. GCC option -mbackchain enables it. Quoting Martin Schwidefsky [1]: "The compiler is called with the -mbackchain option, all normal C function will store the backchain in the function prologue. All functions written in assembler code should do the same, if you find one that does not we should fix that. The end result is that a task that *voluntarily* called schedule() should have a proper backchain at all times. Dependent on the use case this may or may not be enough. Asynchronous interrupts may stop the CPU at the beginning of a function, if kernel preemption is enabled we can end up with a broken backchain. The production kernels for IBM Z are all compiled *without* kernel preemption. So yes, we might get away without the objtool support. On a side-note, we do have a line item to implement the ORC unwinder for the kernel, that includes the objtool support. Once we have that we can drop the -mbackchain option for the kernel build. That gives us a nice little performance benefit. I hope that the change from backchain to the ORC unwinder will not be too hard to implement in the livepatch tools." Since -mbackchain is enabled by default when the kernel is compiled, the call chain backtracing should be currently ensured and objtool should not be necessary for livepatch purposes. Regarding the second issue, stack corruptions and non-reliable states have to be recognized by the unwinder. Mainly it means to detect preemption or page faults, the end of the task stack must be reached, return addresses must be valid text addresses and hacks like function graph tracing and kretprobes must be properly detected. Unwinding a running task's stack is not a problem, because there is a livepatch requirement that every checked task is blocked, except for the current task. Due to that, the implementation can be much simpler compared to the existing non-reliable infrastructure. We can consider a task's kernel/thread stack only and skip the other stacks. [1] 20180912121106.31ffa97c@mschwideX1 [not archived on lore.kernel.org] Link: https://lkml.kernel.org/r/[email protected] Reviewed-by: Heiko Carstens <[email protected]> Tested-by: Miroslav Benes <[email protected]> Signed-off-by: Miroslav Benes <[email protected]> Signed-off-by: Vasily Gorbik <[email protected]>
1 parent be2d11b commit aa137a6

File tree

2 files changed

+44
-0
lines changed

2 files changed

+44
-0
lines changed

arch/s390/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ config S390
170170
select HAVE_PERF_EVENTS
171171
select HAVE_RCU_TABLE_FREE
172172
select HAVE_REGS_AND_STACK_ACCESS_API
173+
select HAVE_RELIABLE_STACKTRACE
173174
select HAVE_RSEQ
174175
select HAVE_SYSCALL_TRACEPOINTS
175176
select HAVE_VIRT_CPU_ACCOUNTING

arch/s390/kernel/stacktrace.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/stacktrace.h>
1010
#include <asm/stacktrace.h>
1111
#include <asm/unwind.h>
12+
#include <asm/kprobes.h>
1213

1314
void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
1415
struct task_struct *task, struct pt_regs *regs)
@@ -22,3 +23,45 @@ void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
2223
break;
2324
}
2425
}
26+
27+
/*
28+
* This function returns an error if it detects any unreliable features of the
29+
* stack. Otherwise it guarantees that the stack trace is reliable.
30+
*
31+
* If the task is not 'current', the caller *must* ensure the task is inactive.
32+
*/
33+
int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry,
34+
void *cookie, struct task_struct *task)
35+
{
36+
struct unwind_state state;
37+
unsigned long addr;
38+
39+
unwind_for_each_frame(&state, task, NULL, 0) {
40+
if (state.stack_info.type != STACK_TYPE_TASK)
41+
return -EINVAL;
42+
43+
if (state.regs)
44+
return -EINVAL;
45+
46+
addr = unwind_get_return_address(&state);
47+
if (!addr)
48+
return -EINVAL;
49+
50+
#ifdef CONFIG_KPROBES
51+
/*
52+
* Mark stacktraces with kretprobed functions on them
53+
* as unreliable.
54+
*/
55+
if (state.ip == (unsigned long)kretprobe_trampoline)
56+
return -EINVAL;
57+
#endif
58+
59+
if (!consume_entry(cookie, addr, false))
60+
return -EINVAL;
61+
}
62+
63+
/* Check for stack corruption */
64+
if (unwind_error(&state))
65+
return -EINVAL;
66+
return 0;
67+
}

0 commit comments

Comments
 (0)