ISSUE: gitee.com/openeuler/kernel/issues/I6DK3O
Chen Zhongjin (2): x86/unwind: Fix orc entry for paravirt {save,restore}_fl x86/unwind: Fix check_paravirt() calls orc_find() before declaration
arch/x86/kernel/unwind_orc.c | 45 +++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-)
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I6DK3O CVE: NA
--------------------------------
When CONFIG_PARAVIRT_XXL is enabled, the code of {save,restore}_fl is defined as:
ff 14 25 00 00 00 00 callq *0x0
which will be patched to call the xen paravirt function, or native implementation, in 'paravirt_patch_64.c':
pushfq; popq %rax // for native_save_fl pushq %rdi; popfq // for native_restore_fl
The orc metadata is generated with insn 'callq', so it can become inconsistent with the real insn 'push;pop'. This makes stacktrace on the 'pop' insn fail and incorrect stacktrace result can be returned.
To prevent reliable stacktrace broken, check the insns when unwind pt_regs stack frame:
When there are 'push;pop' combination and both insns don't change orc entry, it means the stack state is inconsistent with orc on pop. Add one slot to sp_offset for on original orc entry to get the correct orc entry.
Signed-off-by: Chen Zhongjin chenzhongjin@huawei.com Reviewed-by: Xu Kuohai xukuohai@huawei.com --- arch/x86/kernel/unwind_orc.c | 43 ++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+)
diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c index d557a545f4bc5..055a9df84de46 100644 --- a/arch/x86/kernel/unwind_orc.c +++ b/arch/x86/kernel/unwind_orc.c @@ -146,6 +146,34 @@ static struct orc_entry orc_fp_entry = { .end = 0, };
+#ifdef CONFIG_PARAVIRT_XXL +static bool check_paravirt(struct unwind_state *state, struct orc_entry *orc) +{ + u8 *ip = (u8 *)state->ip; + + /* + * In paravirt_patch.c, patched paravirt opcode should be: + * pushfq; popq %rax // 0x9c 0x58 + * pushq %rdi; popfq // 0x57 0x9d + * + * Error unwinding only happens when: + * 1. In irq or preempt context. + * 2. Current insn is popq, and it doesn't change orc. + * 3. Last insn doesn't change orc, checking it first to + * promise ip - 1 is valid. + * 4. Last byte fits pushf. + */ + if (state->regs && orc->type == UNWIND_HINT_TYPE_CALL && + (ip[0] == 0x58 || ip[0] == 0x9d) && + orc == orc_find((unsigned long)(ip + 1)) && + orc == orc_find((unsigned long)(ip - 1)) && + (ip[-1] == 0x9c || ip[-1] == 0x57)) + return true; + + return false; +} +#endif + static struct orc_entry *orc_find(unsigned long ip) { static struct orc_entry *orc; @@ -425,6 +453,9 @@ bool unwind_next_frame(struct unwind_state *state) enum stack_type prev_type = state->stack_info.type; struct orc_entry *orc; bool indirect = false; +#ifdef CONFIG_PARAVIRT_XXL + struct orc_entry para_orc; +#endif
if (unwind_done(state)) return false; @@ -457,6 +488,18 @@ bool unwind_next_frame(struct unwind_state *state) state->error = true; }
+#ifdef CONFIG_PARAVIRT_XXL + /* + * When hitting paravirt POP insn, the orc entry should add + * one slot for PUSH insn. + */ + if (!state->error && check_paravirt(state, orc)) { + para_orc = *orc; + para_orc.sp_offset += sizeof(long); + orc = ¶_orc; + } +#endif + /* End-of-stack check for kernel threads: */ if (orc->sp_reg == ORC_REG_UNDEFINED) { if (!orc->end)
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I6DK3O CVE: NA
--------------------------------
check_paravirt() calls orc_find() before its implementation code.
If CONFIG_DYNAMIC_FTRACE is enabled, orc_find() will be declared earlier and compiling will not fail. Otherwise it will fail for "implicit declaration of function 'orc_find'".
Move declaration of orc_find() out of CONFIG_DYNAMIC_FTRACE macro to fix this.
Fixes: cbb12ea4718a ("[Huawei] x86/unwind: Fix orc entry for paravirt {save,restore}_fl") Signed-off-by: Chen Zhongjin chenzhongjin@huawei.com Reviewed-by: Xu Kuohai xukuohai@huawei.com --- arch/x86/kernel/unwind_orc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c index 055a9df84de46..9452ba625f670 100644 --- a/arch/x86/kernel/unwind_orc.c +++ b/arch/x86/kernel/unwind_orc.c @@ -77,9 +77,9 @@ static struct orc_entry *orc_module_find(unsigned long ip) } #endif
-#ifdef CONFIG_DYNAMIC_FTRACE static struct orc_entry *orc_find(unsigned long ip);
+#ifdef CONFIG_DYNAMIC_FTRACE /* * Ftrace dynamic trampolines do not have orc entries of their own. * But they are copies of the ftrace entries that are static and
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/968 邮件列表地址: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/thread/C2...
FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/968 Mailing list address: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/thread/C2...