Skip to content

Commit 62b672c

Browse files
hcahcaAlexander Gordeev
authored andcommitted
s390/stackstrace: Detect vdso stack frames
Clear the backchain of the extra stack frame added by the vdso user wrapper code. This allows the user stack walker to detect and skip the non-standard stack frame. Without this an incorrect instruction pointer would be added to stack traces, and stack frame walking would be continued with a more or less random back chain. Fixes: aa44433 ("s390: add USER_STACKTRACE support") Reviewed-by: Jens Remus <[email protected]> Signed-off-by: Heiko Carstens <[email protected]> Signed-off-by: Alexander Gordeev <[email protected]>
1 parent be72ea0 commit 62b672c

File tree

5 files changed

+36
-8
lines changed

5 files changed

+36
-8
lines changed

arch/s390/include/asm/processor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ void cpu_detect_mhz_feature(void);
9898

9999
extern const struct seq_operations cpuinfo_op;
100100
extern void execve_tail(void);
101+
unsigned long vdso_text_size(void);
101102
unsigned long vdso_size(void);
102103

103104
/*

arch/s390/kernel/asm-offsets.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ int main(void)
6666
OFFSET(__SF_SIE_CONTROL_PHYS, stack_frame, sie_control_block_phys);
6767
DEFINE(STACK_FRAME_OVERHEAD, sizeof(struct stack_frame));
6868
BLANK();
69+
OFFSET(__SFUSER_BACKCHAIN, stack_frame_user, back_chain);
6970
DEFINE(STACK_FRAME_USER_OVERHEAD, sizeof(struct stack_frame_user));
7071
OFFSET(__SFVDSO_RETURN_ADDRESS, stack_frame_vdso_wrapper, return_address);
7172
DEFINE(STACK_FRAME_VDSO_OVERHEAD, sizeof(struct stack_frame_vdso_wrapper));

arch/s390/kernel/stacktrace.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,16 @@ static inline bool ip_invalid(unsigned long ip)
9292
return false;
9393
}
9494

95+
static inline bool ip_within_vdso(unsigned long ip)
96+
{
97+
return in_range(ip, current->mm->context.vdso_base, vdso_text_size());
98+
}
99+
95100
void arch_stack_walk_user_common(stack_trace_consume_fn consume_entry, void *cookie,
96101
struct perf_callchain_entry_ctx *entry,
97102
const struct pt_regs *regs, bool perf)
98103
{
104+
struct stack_frame_vdso_wrapper __user *sf_vdso;
99105
struct stack_frame_user __user *sf;
100106
unsigned long ip, sp;
101107
bool first = true;
@@ -112,11 +118,25 @@ void arch_stack_walk_user_common(stack_trace_consume_fn consume_entry, void *coo
112118
while (1) {
113119
if (__get_user(sp, &sf->back_chain))
114120
break;
121+
/*
122+
* VDSO entry code has a non-standard stack frame layout.
123+
* See VDSO user wrapper code for details.
124+
*/
125+
if (!sp && ip_within_vdso(ip)) {
126+
sf_vdso = (void __user *)sf;
127+
if (__get_user(ip, &sf_vdso->return_address))
128+
break;
129+
sp = (unsigned long)sf + STACK_FRAME_VDSO_OVERHEAD;
130+
sf = (void __user *)sp;
131+
if (__get_user(sp, &sf->back_chain))
132+
break;
133+
} else {
134+
sf = (void __user *)sp;
135+
if (__get_user(ip, &sf->gprs[8]))
136+
break;
137+
}
115138
/* Sanity check: ABI requires SP to be 8 byte aligned. */
116-
if (!sp || sp & 0x7)
117-
break;
118-
sf = (void __user *)sp;
119-
if (__get_user(ip, &sf->gprs[8]))
139+
if (sp & 0x7)
120140
break;
121141
if (ip_invalid(ip)) {
122142
/*

arch/s390/kernel/vdso.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,17 +210,22 @@ static unsigned long vdso_addr(unsigned long start, unsigned long len)
210210
return addr;
211211
}
212212

213-
unsigned long vdso_size(void)
213+
unsigned long vdso_text_size(void)
214214
{
215-
unsigned long size = VVAR_NR_PAGES * PAGE_SIZE;
215+
unsigned long size;
216216

217217
if (is_compat_task())
218-
size += vdso32_end - vdso32_start;
218+
size = vdso32_end - vdso32_start;
219219
else
220-
size += vdso64_end - vdso64_start;
220+
size = vdso64_end - vdso64_start;
221221
return PAGE_ALIGN(size);
222222
}
223223

224+
unsigned long vdso_size(void)
225+
{
226+
return vdso_text_size() + VVAR_NR_PAGES * PAGE_SIZE;
227+
}
228+
224229
int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
225230
{
226231
unsigned long addr = VDSO_BASE;

arch/s390/kernel/vdso64/vdso_user_wrapper.S

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ __kernel_\func:
2323
CFI_VAL_OFFSET 15,-STACK_FRAME_USER_OVERHEAD
2424
stg %r14,__SFVDSO_RETURN_ADDRESS(%r15)
2525
CFI_REL_OFFSET 14,__SFVDSO_RETURN_ADDRESS
26+
xc __SFUSER_BACKCHAIN(8,%r15),__SFUSER_BACKCHAIN(%r15)
2627
brasl %r14,__s390_vdso_\func
2728
lg %r14,__SFVDSO_RETURN_ADDRESS(%r15)
2829
CFI_RESTORE 14

0 commit comments

Comments
 (0)