Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

unwind: Implement compat fp unwind

It is important to be able to unwind compat tasks too.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20250924080119.613695709@infradead.org

+30 -11
+1
include/linux/unwind_user_types.h
··· 36 36 unsigned long ip; 37 37 unsigned long sp; 38 38 unsigned long fp; 39 + unsigned int ws; 39 40 enum unwind_user_type current_type; 40 41 unsigned int available_types; 41 42 bool done;
+29 -11
kernel/unwind/user.c
··· 8 8 #include <linux/unwind_user.h> 9 9 #include <linux/uaccess.h> 10 10 11 - static const struct unwind_user_frame fp_frame = { 12 - ARCH_INIT_USER_FP_FRAME 13 - }; 14 - 15 11 #define for_each_user_frame(state) \ 16 12 for (unwind_user_start(state); !(state)->done; unwind_user_next(state)) 17 13 14 + static inline int 15 + get_user_word(unsigned long *word, unsigned long base, int off, unsigned int ws) 16 + { 17 + unsigned long __user *addr = (void __user *)base + off; 18 + #ifdef CONFIG_COMPAT 19 + if (ws == sizeof(int)) { 20 + unsigned int data; 21 + int ret = get_user(data, (unsigned int __user *)addr); 22 + *word = data; 23 + return ret; 24 + } 25 + #endif 26 + return get_user(*word, addr); 27 + } 28 + 18 29 static int unwind_user_next_fp(struct unwind_user_state *state) 19 30 { 20 - const struct unwind_user_frame *frame = &fp_frame; 31 + const struct unwind_user_frame frame = { 32 + ARCH_INIT_USER_FP_FRAME(state->ws) 33 + }; 21 34 unsigned long cfa, fp, ra; 22 35 23 - if (frame->use_fp) { 36 + if (frame.use_fp) { 24 37 if (state->fp < state->sp) 25 38 return -EINVAL; 26 39 cfa = state->fp; ··· 42 29 } 43 30 44 31 /* Get the Canonical Frame Address (CFA) */ 45 - cfa += frame->cfa_off; 32 + cfa += frame.cfa_off; 46 33 47 34 /* stack going in wrong direction? */ 48 35 if (cfa <= state->sp) 49 36 return -EINVAL; 50 37 51 38 /* Make sure that the address is word aligned */ 52 - if (cfa & (sizeof(long) - 1)) 39 + if (cfa & (state->ws - 1)) 53 40 return -EINVAL; 54 41 55 42 /* Find the Return Address (RA) */ 56 - if (get_user(ra, (unsigned long *)(cfa + frame->ra_off))) 43 + if (get_user_word(&ra, cfa, frame.ra_off, state->ws)) 57 44 return -EINVAL; 58 45 59 - if (frame->fp_off && get_user(fp, (unsigned long __user *)(cfa + frame->fp_off))) 46 + if (frame.fp_off && get_user_word(&fp, cfa, frame.fp_off, state->ws)) 60 47 return -EINVAL; 61 48 62 49 state->ip = ra; 63 50 state->sp = cfa; 64 - if (frame->fp_off) 51 + if (frame.fp_off) 65 52 state->fp = fp; 66 53 return 0; 67 54 } ··· 113 100 state->ip = instruction_pointer(regs); 114 101 state->sp = user_stack_pointer(regs); 115 102 state->fp = frame_pointer(regs); 103 + state->ws = unwind_user_word_size(regs); 104 + if (!state->ws) { 105 + state->done = true; 106 + return -EINVAL; 107 + } 116 108 117 109 return 0; 118 110 }