x86,objtool: Split UNWIND_HINT_EMPTY in two
Subsystems (9)
Josh Poimboeuf
maintainercover x86,objtool: Split UNWIND_HINT_EMPTY in two
Based on tip/objtool/core.
Mark reported that the ORC unwinder incorrectly marks an unwind as reliable when the unwind terminates prematurely in the dark corners of return_to_handler() due to lack of information about the next frame.
The problem is UNWIND_HINT_EMPTY is used in two different situations:
end-of-stack marker and undefined stack state.
Split it up into UNWIND_HINT_END_OF_STACK and UNWIND_HINT_UNDEFINED.
Josh Poimboeuf (6):
objtool: Add objtool_types.h
objtool: Use relative pointers for annotations
objtool: Change UNWIND_HINT() argument order x86,objtool: Introduce ORC_TYPE_*
x86,objtool: Separate unret validation from unwind hints x86,objtool: Split UNWIND_HINT_EMPTY in two
.../livepatch/reliable-stacktrace.rst | 2 +- MAINTAINERS | 2 +- arch/x86/entry/entry_64.S | 26 +-- arch/x86/include/asm/nospec-branch.h | 14 +- arch/x86/include/asm/orc_types.h | 12 +- arch/x86/include/asm/unwind_hints.h | 18 +- arch/x86/kernel/ftrace_64.S | 2 +- arch/x86/kernel/head_64.S | 17 +- arch/x86/kernel/relocate_kernel_64.S | 10 +- arch/x86/kernel/unwind_orc.c | 27 ++- arch/x86/lib/retpoline.S | 6 +- arch/x86/platform/pvh/head.S | 2 +- arch/x86/xen/xen-asm.S | 4 +- arch/x86/xen/xen-head.S | 4 +- include/linux/objtool.h | 81 +++---- include/linux/objtool_types.h | 57 +++++ scripts/sorttable.h | 2 +- tools/arch/x86/include/asm/orc_types.h | 12 +- tools/include/linux/objtool.h | 200 ------------------ tools/include/linux/objtool_types.h | 57 +++++ tools/objtool/check.c | 69 ++++-- tools/objtool/include/objtool/check.h | 4 +- tools/objtool/orc_dump.c | 15 +- tools/objtool/orc_gen.c | 43 ++-- tools/objtool/sync-check.sh | 2 +- 25 files changed, 314 insertions(+), 374 deletions(-) create mode 100644 include/linux/objtool_types.h delete mode 100644 tools/include/linux/objtool.h create mode 100644 tools/include/linux/objtool_types.h
Signature · 1 line
2.39.1
Josh Poimboeuf
maintainerPATCH 1/6 objtool: Add objtool_types.h
Reduce the amount of header sync churn by splitting the shared objtool.h types into a new file.
--- MAINTAINERS | 2 +- include/linux/objtool.h | 42 +----- include/linux/objtool_types.h | 48 +++++++ tools/include/linux/objtool.h | 200 ---------------------------- tools/include/linux/objtool_types.h | 48 +++++++ tools/objtool/check.c | 2 +- tools/objtool/orc_dump.c | 2 +- tools/objtool/orc_gen.c | 2 +- tools/objtool/sync-check.sh | 2 +- 9 files changed, 102 insertions(+), 246 deletions(-) create mode 100644 include/linux/objtool_types.h delete mode 100644 tools/include/linux/objtool.h create mode 100644 tools/include/linux/objtool_types.h
MAINTAINERS +1 -1
@@ -14988,8 +14988,8 @@ OBJTOOL M: Josh Poimboeuf <[email protected]> M: Peter Zijlstra <[email protected]> S: Supported +F: include/linux/objtool*.h F: tools/objtool/ -F: include/linux/objtool.h OCELOT ETHERNET SWITCH DRIVER M: Vladimir Oltean <[email protected]>
include/linux/objtool.h +1 -41
48 lines not on this page · raw message
include/linux/objtool_types.h new file +48 -0
48 lines not on this page · raw message
tools/include/linux/objtool.h deleted +0 -200
200 lines not on this page · raw message
tools/include/linux/objtool_types.h new file +48 -0
48 lines not on this page · raw message
tools/objtool/check.c +1 -1
@@ -17,7 +17,7 @@#include <objtool/warn.h> #include <objtool/endianness.h> -#include <linux/objtool.h> +#include <linux/objtool_types.h> #include <linux/hashtable.h> #include <linux/kernel.h> #include <linux/static_call_types.h>
tools/objtool/orc_dump.c +1 -1
@@ -4,7 +4,7 @@*/ #include <unistd.h> -#include <linux/objtool.h> +#include <linux/objtool_types.h> #include <asm/orc_types.h> #include <objtool/objtool.h> #include <objtool/warn.h>
tools/objtool/orc_gen.c +1 -1
@@ -6,7 +6,7 @@#include <stdlib.h> #include <string.h> -#include <linux/objtool.h> +#include <linux/objtool_types.h> #include <asm/orc_types.h> #include <objtool/check.h>
tools/objtool/sync-check.sh +1 -1
@@ -6,7 +6,7 @@ if [ -z "$SRCARCH" ]; then exit 1 fi -FILES="include/linux/objtool.h" +FILES="include/linux/objtool_types.h" if [ "$SRCARCH" = "x86" ]; then FILES="$FILES
Signature · 1 line
2.39.1
[tip: objtool/core] objtool: Add objtool_types.h
The following commit has been merged into the objtool/core branch of tip:
The following commit has been merged into the objtool/core branch of tip:
Commit-ID: f7515d9fe8fc4b80754cd4d98a5fcaee84adeebb Gitweb: https://git.kernel.org/tip/f7515d9fe8fc4b80754cd4d98a5fcaee84adeebb Author: Josh Poimboeuf <[email protected]> AuthorDate: Wed, 01 Mar 2023 07:13:07 -08:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Thu, 23 Mar 2023 23:18:56 +01:00
objtool: Add objtool_types.h
Reduce the amount of header sync churn by splitting the shared objtool.h types into a new file.
--- MAINTAINERS | 2 +- include/linux/objtool.h | 42 +------ include/linux/objtool_types.h | 48 ++++++- tools/include/linux/objtool.h | 200 +--------------------------- tools/include/linux/objtool_types.h | 48 ++++++- tools/objtool/check.c | 2 +- tools/objtool/orc_dump.c | 2 +- tools/objtool/orc_gen.c | 2 +- tools/objtool/sync-check.sh | 2 +- 9 files changed, 102 insertions(+), 246 deletions(-) create mode 100644 include/linux/objtool_types.h delete mode 100644 tools/include/linux/objtool.h create mode 100644 tools/include/linux/objtool_types.h
MAINTAINERS +1 -1
@@ -15090,8 +15090,8 @@ OBJTOOL M: Josh Poimboeuf <[email protected]> M: Peter Zijlstra <[email protected]> S: Supported +F: include/linux/objtool*.h F: tools/objtool/ -F: include/linux/objtool.h OCELOT ETHERNET SWITCH DRIVER M: Vladimir Oltean <[email protected]>
include/linux/objtool.h +1 -41
48 lines not on this page · raw message
include/linux/objtool_types.h new file +48 -0
48 lines not on this page · raw message
tools/include/linux/objtool.h deleted +0 -200
200 lines not on this page · raw message
tools/include/linux/objtool_types.h new file +48 -0
48 lines not on this page · raw message
tools/objtool/check.c +1 -1
@@ -17,7 +17,7 @@#include <objtool/warn.h> #include <objtool/endianness.h> -#include <linux/objtool.h> +#include <linux/objtool_types.h> #include <linux/hashtable.h> #include <linux/kernel.h> #include <linux/static_call_types.h>
tools/objtool/orc_dump.c +1 -1
@@ -4,7 +4,7 @@*/ #include <unistd.h> -#include <linux/objtool.h> +#include <linux/objtool_types.h> #include <asm/orc_types.h> #include <objtool/objtool.h> #include <objtool/warn.h>
tools/objtool/orc_gen.c +1 -1
@@ -6,7 +6,7 @@#include <stdlib.h> #include <string.h> -#include <linux/objtool.h> +#include <linux/objtool_types.h> #include <asm/orc_types.h> #include <objtool/check.h>
tools/objtool/sync-check.sh +1 -1
@@ -6,7 +6,7 @@ if [ -z "$SRCARCH" ]; then exit 1 fi -FILES="include/linux/objtool.h" +FILES="include/linux/objtool_types.h" if [ "$SRCARCH" = "x86" ]; then FILES="$FILES
Josh Poimboeuf
maintainerPATCH 2/6 objtool: Use relative pointers for annotations
In reply to Josh PoimboeufThey produce the needed relocations while using half the space.
--- arch/x86/include/asm/nospec-branch.h | 6 +++--- include/linux/objtool.h | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-)
arch/x86/include/asm/nospec-branch.h +3 -3
@@ -194,9 +194,9 @@* builds. */ .macro ANNOTATE_RETPOLINE_SAFE - .Lannotate_\@: +.Lhere_\@: .pushsection .discard.retpoline_safe - _ASM_PTR .Lannotate_\@ + .long .Lhere_\@ - . .popsection .endm
@@ -318,7 +318,7 @@#define ANNOTATE_RETPOLINE_SAFE \ "999:\n\t" \ ".pushsection .discard.retpoline_safe\n\t" \ - _ASM_PTR " 999b\n\t" \ + ".long 999b - .\n\t" \ ".popsection\n\t"typedef u8 retpoline_thunk_t [RETPOLINE_THUNK_SIZE ];
include/linux/objtool.h +6 -6
@@ -49,7 +49,7 @@#define ANNOTATE_NOENDBR \ "986: \n\t" \ ".pushsection .discard.noendbr\n\t" \ - _ASM_PTR " 986b\n\t" \ + ".long 986b - .\n\t" \ ".popsection\n\t"#define ASM_REACHABLE \
@@ -67,7 +67,7 @@#define ANNOTATE_INTRA_FUNCTION_CALL \ 999: \ .pushsection .discard.intra_function_calls; \ - .long 999b; \ + .long 999b - .; \ .popsection;/*
@@ -92,10 +92,10 @@* inconsistencies. */ .macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0 -.Lunwind_hint_ip_\@: +.Lhere_\@: .pushsection .discard.unwind_hints/* struct unwind_hint */ - .long .Lunwind_hint_ip_\@ - . + .long .Lhere_\@ - . .short \sp_offset .byte \sp_reg .byte \type
@@ -107,7 +107,7 @@ .macro STACK_FRAME_NON_STANDARD func:req .pushsection .discard.func_stack_frame_non_standard,"aw" - _ASM_PTR \func + .long \func - . .popsection .endm
@@ -120,7 +120,7 @@ .macro ANNOTATE_NOENDBR .Lhere_\@: .pushsection .discard.noendbr - .quad .Lhere_\@ + .long .Lhere_\@ - . .popsection .endm
Signature · 1 line
2.39.1
[tip: objtool/core] objtool: Use relative pointers for annotations
The following commit has been merged into the objtool/core branch of tip:
The following commit has been merged into the objtool/core branch of tip:
Commit-ID: 1c0c1faf5692c18c127d044ecc0cc92c7bab3477 Gitweb: https://git.kernel.org/tip/1c0c1faf5692c18c127d044ecc0cc92c7bab3477 Author: Josh Poimboeuf <[email protected]> AuthorDate: Wed, 01 Mar 2023 07:13:08 -08:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Thu, 23 Mar 2023 23:18:56 +01:00
objtool: Use relative pointers for annotations
They produce the needed relocations while using half the space.
--- arch/x86/include/asm/nospec-branch.h | 6 +++--- include/linux/objtool.h | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-)
arch/x86/include/asm/nospec-branch.h +3 -3
@@ -194,9 +194,9 @@* builds. */ .macro ANNOTATE_RETPOLINE_SAFE - .Lannotate_\@: +.Lhere_\@: .pushsection .discard.retpoline_safe - _ASM_PTR .Lannotate_\@ + .long .Lhere_\@ - . .popsection .endm
@@ -318,7 +318,7 @@#define ANNOTATE_RETPOLINE_SAFE \ "999:\n\t" \ ".pushsection .discard.retpoline_safe\n\t" \ - _ASM_PTR " 999b\n\t" \ + ".long 999b - .\n\t" \ ".popsection\n\t"typedef u8 retpoline_thunk_t [RETPOLINE_THUNK_SIZE ];
include/linux/objtool.h +6 -6
@@ -49,7 +49,7 @@#define ANNOTATE_NOENDBR \ "986: \n\t" \ ".pushsection .discard.noendbr\n\t" \ - _ASM_PTR " 986b\n\t" \ + ".long 986b - .\n\t" \ ".popsection\n\t"#define ASM_REACHABLE \
@@ -67,7 +67,7 @@#define ANNOTATE_INTRA_FUNCTION_CALL \ 999: \ .pushsection .discard.intra_function_calls; \ - .long 999b; \ + .long 999b - .; \ .popsection;/*
@@ -92,10 +92,10 @@* inconsistencies. */ .macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0 -.Lunwind_hint_ip_\@: +.Lhere_\@: .pushsection .discard.unwind_hints/* struct unwind_hint */ - .long .Lunwind_hint_ip_\@ - . + .long .Lhere_\@ - . .short \sp_offset .byte \sp_reg .byte \type
@@ -107,7 +107,7 @@ .macro STACK_FRAME_NON_STANDARD func:req .pushsection .discard.func_stack_frame_non_standard,"aw" - _ASM_PTR \func + .long \func - . .popsection .endm
@@ -120,7 +120,7 @@ .macro ANNOTATE_NOENDBR .Lhere_\@: .pushsection .discard.noendbr - .quad .Lhere_\@ + .long .Lhere_\@ - . .popsection .endm
Josh Poimboeuf
maintainerPATCH 3/6 objtool: Change UNWIND_HINT() argument order
In reply to Josh PoimboeufThe most important argument is 'type', make that one first.
--- arch/x86/include/asm/unwind_hints.h | 2 +- include/linux/objtool.h | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-)
arch/x86/include/asm/unwind_hints.h +1 -1
@@ -67,7 +67,7 @@#else #define UNWIND_HINT_FUNC \ - UNWIND_HINT(ORC_REG_SP, 8, UNWIND_HINT_TYPE_FUNC, 0, 0) + UNWIND_HINT(UNWIND_HINT_TYPE_FUNC, ORC_REG_SP, 8, 0, 0)#endif /* __ASSEMBLY__ */
include/linux/objtool.h +2 -3
@@ -10,7 +10,7 @@#ifndef __ASSEMBLY__ -#define UNWIND_HINT (sp_reg, sp_offset, type, signal, end) \ +#define UNWIND_HINT (type, sp_reg, sp_offset, signal, end) \ "987: \n\t" \ ".pushsection .discard.unwind_hints\n\t" \/* struct unwind_hint */ \
@@ -137,8 +137,7 @@#ifndef __ASSEMBLY__ -#define UNWIND_HINT (sp_reg, sp_offset, type, signal, end) \ - "\n\t" +#define UNWIND_HINT (type, sp_reg, sp_offset, signal, end) "\n\t"#define STACK_FRAME_NON_STANDARD (func)#define STACK_FRAME_NON_STANDARD_FP (func)#define ANNOTATE_NOENDBR
Signature · 1 line
2.39.1
[tip: objtool/core] objtool: Change UNWIND_HINT() argument order
The following commit has been merged into the objtool/core branch of tip:
The following commit has been merged into the objtool/core branch of tip:
Commit-ID: d88ebba45dfe67114a6ac8c6514f2c65b6ed64c7 Gitweb: https://git.kernel.org/tip/d88ebba45dfe67114a6ac8c6514f2c65b6ed64c7 Author: Josh Poimboeuf <[email protected]> AuthorDate: Wed, 01 Mar 2023 07:13:09 -08:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Thu, 23 Mar 2023 23:18:57 +01:00
objtool: Change UNWIND_HINT() argument order
The most important argument is 'type', make that one first.
--- arch/x86/include/asm/unwind_hints.h | 2 +- include/linux/objtool.h | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-)
arch/x86/include/asm/unwind_hints.h +1 -1
@@ -67,7 +67,7 @@#else #define UNWIND_HINT_FUNC \ - UNWIND_HINT(ORC_REG_SP, 8, UNWIND_HINT_TYPE_FUNC, 0, 0) + UNWIND_HINT(UNWIND_HINT_TYPE_FUNC, ORC_REG_SP, 8, 0, 0)#endif /* __ASSEMBLY__ */
include/linux/objtool.h +2 -3
@@ -10,7 +10,7 @@#ifndef __ASSEMBLY__ -#define UNWIND_HINT (sp_reg, sp_offset, type, signal, end) \ +#define UNWIND_HINT (type, sp_reg, sp_offset, signal, end) \ "987: \n\t" \ ".pushsection .discard.unwind_hints\n\t" \/* struct unwind_hint */ \
@@ -137,8 +137,7 @@#ifndef __ASSEMBLY__ -#define UNWIND_HINT (sp_reg, sp_offset, type, signal, end) \ - "\n\t" +#define UNWIND_HINT (type, sp_reg, sp_offset, signal, end) "\n\t"#define STACK_FRAME_NON_STANDARD (func)#define STACK_FRAME_NON_STANDARD_FP (func)#define ANNOTATE_NOENDBR
Josh Poimboeuf
maintainerPATCH 4/6 x86,objtool: Introduce ORC_TYPE_*
In reply to Josh PoimboeufUnwind hints and ORC entry types are two distinct things. Separate them out more explicitly.
--- arch/x86/include/asm/orc_types.h | 4 ++++ arch/x86/kernel/unwind_orc.c | 12 ++++++------ include/linux/objtool_types.h | 1 + tools/arch/x86/include/asm/orc_types.h | 4 ++++ tools/include/linux/objtool_types.h | 1 + tools/objtool/orc_dump.c | 7 +++---- tools/objtool/orc_gen.c | 19 +++++++++++++++++-- 7 files changed, 36 insertions(+), 12 deletions(-)
arch/x86/include/asm/orc_types.h +4 -0
@@ -39,6 +39,10 @@#define ORC_REG_SP_INDIRECT 9#define ORC_REG_MAX 15 +#define ORC_TYPE_CALL 0 +#define ORC_TYPE_REGS 1 +#define ORC_TYPE_REGS_PARTIAL 2 +#ifndef __ASSEMBLY__#include <asm/byteorder.h>
arch/x86/kernel/unwind_orc.c +6 -6
@@ -133,7 +133,7 @@ static struct orc_entry null_orc_entry = { .sp_offset = sizeof(long), .sp_reg = ORC_REG_SP, .bp_reg = ORC_REG_UNDEFINED, - .type = UNWIND_HINT_TYPE_CALL + .type = ORC_TYPE_CALL };#ifdef CONFIG_CALL_THUNKS
@@ -153,7 +153,7 @@ static struct orc_entry *orc_callthunk_find(unsigned long ip)/* Fake frame pointer entry -- used as a fallback for generated code */ static struct orc_entry orc_fp_entry = { - .type =UNWIND_HINT_TYPE_CALL , + .type =ORC_TYPE_CALL , .sp_reg =ORC_REG_BP , .sp_offset =16 , .bp_reg =ORC_REG_PREV_SP ,
@@ -554,7 +554,7 @@ bool unwind_next_frame(struct unwind_state *state)/* Find IP, SP and possibly regs: */ switch (orc->type) { -case UNWIND_HINT_TYPE_CALL : +case ORC_TYPE_CALL : ip_p = sp -sizeof (long );if (!deref_stack_reg (state, ip_p, &state->ip))
@@ -567,7 +567,7 @@ bool unwind_next_frame(struct unwind_state *state) state->prev_regs =NULL ;break ; -case UNWIND_HINT_TYPE_REGS : +case ORC_TYPE_REGS :if (!deref_stack_regs (state, sp, &state->ip, &state->sp)) {orc_warn_current ("can't access registers at %pB\n" , (void *)orig_ip);
@@ -590,13 +590,13 @@ bool unwind_next_frame(struct unwind_state *state) state->full_regs = true;break ; -case UNWIND_HINT_TYPE_REGS_PARTIAL : +case ORC_TYPE_REGS_PARTIAL :if (!deref_stack_iret_regs (state, sp, &state->ip, &state->sp)) {orc_warn_current ("can't access iret registers at %pB\n" , (void *)orig_ip); goto err; } -/* See UNWIND_HINT_TYPE_REGS case comment. */ +/* See ORC_TYPE_REGS case comment. */ state->ip =unwind_recover_rethook (state, state->ip, (unsigned long *)(state->sp -sizeof (long )));
include/linux/objtool_types.h +1 -0
@@ -40,6 +40,7 @@ struct unwind_hint {#define UNWIND_HINT_TYPE_CALL 0#define UNWIND_HINT_TYPE_REGS 1#define UNWIND_HINT_TYPE_REGS_PARTIAL 2 +/* The below hint types don't have corresponding ORC types */ #define UNWIND_HINT_TYPE_FUNC 3#define UNWIND_HINT_TYPE_ENTRY 4#define UNWIND_HINT_TYPE_SAVE 5
tools/arch/x86/include/asm/orc_types.h +4 -0
@@ -39,6 +39,10 @@#define ORC_REG_SP_INDIRECT 9#define ORC_REG_MAX 15 +#define ORC_TYPE_CALL 0 +#define ORC_TYPE_REGS 1 +#define ORC_TYPE_REGS_PARTIAL 2 +#ifndef __ASSEMBLY__#include <asm/byteorder.h>
tools/include/linux/objtool_types.h +1 -0
@@ -40,6 +40,7 @@ struct unwind_hint {#define UNWIND_HINT_TYPE_CALL 0#define UNWIND_HINT_TYPE_REGS 1#define UNWIND_HINT_TYPE_REGS_PARTIAL 2 +/* The below hint types don't have corresponding ORC types */ #define UNWIND_HINT_TYPE_FUNC 3#define UNWIND_HINT_TYPE_ENTRY 4#define UNWIND_HINT_TYPE_SAVE 5
tools/objtool/orc_dump.c +3 -4
@@ -4,7 +4,6 @@*/ #include <unistd.h> -#include <linux/objtool_types.h> #include <asm/orc_types.h> #include <objtool/objtool.h> #include <objtool/warn.h>
@@ -39,11 +38,11 @@ static const char *reg_name(unsigned int reg)static const char *orc_type_name (unsigned int type) {switch (type) { -case UNWIND_HINT_TYPE_CALL : +case ORC_TYPE_CALL :return "call" ; -case UNWIND_HINT_TYPE_REGS : +case ORC_TYPE_REGS :return "regs" ; -case UNWIND_HINT_TYPE_REGS_PARTIAL : +case ORC_TYPE_REGS_PARTIAL :return "regs (partial)" ;default :return "?" ;
tools/objtool/orc_gen.c +17 -2
@@ -26,6 +26,22 @@ static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi,return 0 ; } +switch (cfi->type) { +case UNWIND_HINT_TYPE_CALL : + orc->type =ORC_TYPE_CALL ; +break ; +case UNWIND_HINT_TYPE_REGS : + orc->type =ORC_TYPE_REGS ; +break ; +case UNWIND_HINT_TYPE_REGS_PARTIAL : + orc->type =ORC_TYPE_REGS_PARTIAL ; +break ; +default : +WARN_FUNC ("unknown unwind hint type %d" , + insn->sec, insn->offset, cfi->type); +return -1 ; + } + orc->end = cfi->end; orc->signal = cfi->signal;
@@ -83,7 +99,6 @@ static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, orc->sp_offset = cfi->cfa.offset; orc->bp_offset = bp->offset; - orc->type = cfi->type;return 0 ; }
@@ -151,7 +166,7 @@ int orc_create(struct objtool_file *file)struct orc_entry null = { .sp_reg =ORC_REG_UNDEFINED , .bp_reg =ORC_REG_UNDEFINED , - .type =UNWIND_HINT_TYPE_CALL , + .type =ORC_TYPE_CALL , };/* Build a deduplicated list of ORC entries: */
Signature · 1 line
2.39.1
[tip: objtool/core] x86,objtool: Introduce ORC_TYPE_*
The following commit has been merged into the objtool/core branch of tip:
The following commit has been merged into the objtool/core branch of tip:
Commit-ID: f902cfdd46aedd2afb3e8033223312dbf5fbb675 Gitweb: https://git.kernel.org/tip/f902cfdd46aedd2afb3e8033223312dbf5fbb675 Author: Josh Poimboeuf <[email protected]> AuthorDate: Wed, 01 Mar 2023 07:13:10 -08:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Thu, 23 Mar 2023 23:18:57 +01:00
x86,objtool: Introduce ORC_TYPE_*
Unwind hints and ORC entry types are two distinct things. Separate them out more explicitly.
--- arch/x86/include/asm/orc_types.h | 4 ++++ arch/x86/kernel/unwind_orc.c | 12 ++++++------ include/linux/objtool_types.h | 1 + tools/arch/x86/include/asm/orc_types.h | 4 ++++ tools/include/linux/objtool_types.h | 1 + tools/objtool/orc_dump.c | 7 +++---- tools/objtool/orc_gen.c | 19 +++++++++++++++++-- 7 files changed, 36 insertions(+), 12 deletions(-)
arch/x86/include/asm/orc_types.h +4 -0
@@ -39,6 +39,10 @@#define ORC_REG_SP_INDIRECT 9#define ORC_REG_MAX 15 +#define ORC_TYPE_CALL 0 +#define ORC_TYPE_REGS 1 +#define ORC_TYPE_REGS_PARTIAL 2 +#ifndef __ASSEMBLY__#include <asm/byteorder.h>
arch/x86/kernel/unwind_orc.c +6 -6
@@ -133,7 +133,7 @@ static struct orc_entry null_orc_entry = { .sp_offset = sizeof(long), .sp_reg = ORC_REG_SP, .bp_reg = ORC_REG_UNDEFINED, - .type = UNWIND_HINT_TYPE_CALL + .type = ORC_TYPE_CALL };#ifdef CONFIG_CALL_THUNKS
@@ -153,7 +153,7 @@ static struct orc_entry *orc_callthunk_find(unsigned long ip)/* Fake frame pointer entry -- used as a fallback for generated code */ static struct orc_entry orc_fp_entry = { - .type =UNWIND_HINT_TYPE_CALL , + .type =ORC_TYPE_CALL , .sp_reg =ORC_REG_BP , .sp_offset =16 , .bp_reg =ORC_REG_PREV_SP ,
@@ -554,7 +554,7 @@ bool unwind_next_frame(struct unwind_state *state)/* Find IP, SP and possibly regs: */ switch (orc->type) { -case UNWIND_HINT_TYPE_CALL : +case ORC_TYPE_CALL : ip_p = sp -sizeof (long );if (!deref_stack_reg (state, ip_p, &state->ip))
@@ -567,7 +567,7 @@ bool unwind_next_frame(struct unwind_state *state) state->prev_regs =NULL ;break ; -case UNWIND_HINT_TYPE_REGS : +case ORC_TYPE_REGS :if (!deref_stack_regs (state, sp, &state->ip, &state->sp)) {orc_warn_current ("can't access registers at %pB\n" , (void *)orig_ip);
@@ -590,13 +590,13 @@ bool unwind_next_frame(struct unwind_state *state) state->full_regs = true;break ; -case UNWIND_HINT_TYPE_REGS_PARTIAL : +case ORC_TYPE_REGS_PARTIAL :if (!deref_stack_iret_regs (state, sp, &state->ip, &state->sp)) {orc_warn_current ("can't access iret registers at %pB\n" , (void *)orig_ip); goto err; } -/* See UNWIND_HINT_TYPE_REGS case comment. */ +/* See ORC_TYPE_REGS case comment. */ state->ip =unwind_recover_rethook (state, state->ip, (unsigned long *)(state->sp -sizeof (long )));
include/linux/objtool_types.h +1 -0
@@ -40,6 +40,7 @@ struct unwind_hint {#define UNWIND_HINT_TYPE_CALL 0#define UNWIND_HINT_TYPE_REGS 1#define UNWIND_HINT_TYPE_REGS_PARTIAL 2 +/* The below hint types don't have corresponding ORC types */ #define UNWIND_HINT_TYPE_FUNC 3#define UNWIND_HINT_TYPE_ENTRY 4#define UNWIND_HINT_TYPE_SAVE 5
tools/arch/x86/include/asm/orc_types.h +4 -0
@@ -39,6 +39,10 @@#define ORC_REG_SP_INDIRECT 9#define ORC_REG_MAX 15 +#define ORC_TYPE_CALL 0 +#define ORC_TYPE_REGS 1 +#define ORC_TYPE_REGS_PARTIAL 2 +#ifndef __ASSEMBLY__#include <asm/byteorder.h>
tools/include/linux/objtool_types.h +1 -0
@@ -40,6 +40,7 @@ struct unwind_hint {#define UNWIND_HINT_TYPE_CALL 0#define UNWIND_HINT_TYPE_REGS 1#define UNWIND_HINT_TYPE_REGS_PARTIAL 2 +/* The below hint types don't have corresponding ORC types */ #define UNWIND_HINT_TYPE_FUNC 3#define UNWIND_HINT_TYPE_ENTRY 4#define UNWIND_HINT_TYPE_SAVE 5
tools/objtool/orc_dump.c +3 -4
@@ -4,7 +4,6 @@*/ #include <unistd.h> -#include <linux/objtool_types.h> #include <asm/orc_types.h> #include <objtool/objtool.h> #include <objtool/warn.h>
@@ -39,11 +38,11 @@ static const char *reg_name(unsigned int reg)static const char *orc_type_name (unsigned int type) {switch (type) { -case UNWIND_HINT_TYPE_CALL : +case ORC_TYPE_CALL :return "call" ; -case UNWIND_HINT_TYPE_REGS : +case ORC_TYPE_REGS :return "regs" ; -case UNWIND_HINT_TYPE_REGS_PARTIAL : +case ORC_TYPE_REGS_PARTIAL :return "regs (partial)" ;default :return "?" ;
tools/objtool/orc_gen.c +17 -2
@@ -26,6 +26,22 @@ static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi,return 0 ; } +switch (cfi->type) { +case UNWIND_HINT_TYPE_CALL : + orc->type =ORC_TYPE_CALL ; +break ; +case UNWIND_HINT_TYPE_REGS : + orc->type =ORC_TYPE_REGS ; +break ; +case UNWIND_HINT_TYPE_REGS_PARTIAL : + orc->type =ORC_TYPE_REGS_PARTIAL ; +break ; +default : +WARN_FUNC ("unknown unwind hint type %d" , + insn->sec, insn->offset, cfi->type); +return -1 ; + } + orc->end = cfi->end; orc->signal = cfi->signal;
@@ -83,7 +99,6 @@ static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, orc->sp_offset = cfi->cfa.offset; orc->bp_offset = bp->offset; - orc->type = cfi->type;return 0 ; }
@@ -151,7 +166,7 @@ int orc_create(struct objtool_file *file)struct orc_entry null = { .sp_reg =ORC_REG_UNDEFINED , .bp_reg =ORC_REG_UNDEFINED , - .type =UNWIND_HINT_TYPE_CALL , + .type =ORC_TYPE_CALL , };/* Build a deduplicated list of ORC entries: */
Josh Poimboeuf
maintainerPATCH 5/6 x86,objtool: Separate unret validation from unwind hints
In reply to Josh PoimboeufThe ENTRY unwind hint type is serving double duty as both an empty unwind hint and an unret validation annotation.
Unret validation is unrelated to unwinding. Separate it out into its own annotation.
--- arch/x86/entry/entry_64.S | 14 +++--- arch/x86/include/asm/nospec-branch.h | 8 ++-- arch/x86/include/asm/unwind_hints.h | 8 +++- arch/x86/kernel/head_64.S | 5 --- include/linux/objtool.h | 16 +++++++ include/linux/objtool_types.h | 5 +-- tools/include/linux/objtool_types.h | 5 +-- tools/objtool/check.c | 65 ++++++++++++++++++--------- tools/objtool/include/objtool/check.h | 4 +- 9 files changed, 85 insertions(+), 45 deletions(-)
arch/x86/entry/entry_64.S +7 -7
@@ -388,9 +388,9 @@ SYM_CODE_START(\asmsym) .if \vector == X86_TRAP_BP /* #BP advances %rip to the next instruction */ - UNWIND_HINT_IRET_REGS offset=\has_error_code*8 signal=0 + UNWIND_HINT_IRET_ENTRY offset=\has_error_code*8 signal=0 .else - UNWIND_HINT_IRET_REGS offset=\has_error_code*8 + UNWIND_HINT_IRET_ENTRY offset=\has_error_code*8 .endif ENDBR
@@ -461,7 +461,7 @@ SYM_CODE_END(\asmsym) */ .macro idtentry_mce_db vector asmsym cfunc SYM_CODE_START(\asmsym) - UNWIND_HINT_IRET_REGS + UNWIND_HINT_IRET_ENTRY ENDBR ASM_CLAC cld
@@ -518,7 +518,7 @@ SYM_CODE_END(\asmsym) */ .macro idtentry_vc vector asmsym cfunc SYM_CODE_START(\asmsym) - UNWIND_HINT_IRET_REGS + UNWIND_HINT_IRET_ENTRY ENDBR ASM_CLAC cld
@@ -582,7 +582,7 @@ SYM_CODE_END(\asmsym) */ .macro idtentry_df vector asmsym cfunc SYM_CODE_START(\asmsym) - UNWIND_HINT_IRET_REGS offset=8 + UNWIND_HINT_IRET_ENTRY offset=8 ENDBR ASM_CLAC cld
@@ -1107,7 +1107,7 @@ SYM_CODE_START(error_entry) FENCE_SWAPGS_KERNEL_ENTRY CALL_DEPTH_ACCOUNT leaq 8(%rsp), %rax /* return pt_regs pointer */ - ANNOTATE_UNRET_END + VALIDATE_UNRET_END RET .Lbstep_iret:
@@ -1153,7 +1153,7 @@ SYM_CODE_END(error_return) * when PAGE_TABLE_ISOLATION is in use. Do not clobber. */ SYM_CODE_START(asm_exc_nmi) - UNWIND_HINT_IRET_REGS + UNWIND_HINT_IRET_ENTRY ENDBR /*
arch/x86/include/asm/nospec-branch.h +4 -4
@@ -210,8 +210,8 @@* Abuse ANNOTATE_RETPOLINE_SAFE on a NOP to indicate UNRET_END, should * eventually turn into it's own annotation. */ -.macro ANNOTATE_UNRET_END -#ifdef CONFIG_DEBUG_ENTRY +.macro VALIDATE_UNRET_END +#if defined(CONFIG_NOINSTR_VALIDATION ) && defined(CONFIG_CPU_UNRET_ENTRY )ANNOTATE_RETPOLINE_SAFE nop#endif
@@ -286,7 +286,7 @@ .macro UNTRAIN_RET#if defined(CONFIG_CPU_UNRET_ENTRY ) || defined(CONFIG_CPU_IBPB_ENTRY ) || \ defined(CONFIG_CALL_DEPTH_TRACKING ) -ANNOTATE_UNRET_END +VALIDATE_UNRET_END ALTERNATIVE_3 "", \CALL_ZEN_UNTRAIN_RET ,X86_FEATURE_UNRET , \ "call entry_ibpb", X86_FEATURE_ENTRY_IBPB, \
@@ -297,7 +297,7 @@ .macro UNTRAIN_RET_FROM_CALL#if defined(CONFIG_CPU_UNRET_ENTRY ) || defined(CONFIG_CPU_IBPB_ENTRY ) || \ defined(CONFIG_CALL_DEPTH_TRACKING ) -ANNOTATE_UNRET_END +VALIDATE_UNRET_END ALTERNATIVE_3 "", \CALL_ZEN_UNTRAIN_RET ,X86_FEATURE_UNRET , \ "call entry_ibpb", X86_FEATURE_ENTRY_IBPB, \
arch/x86/include/asm/unwind_hints.h +7 -1
@@ -12,7 +12,8 @@ .endm .macro UNWIND_HINT_ENTRY - UNWIND_HINT type=UNWIND_HINT_TYPE_ENTRY end=1 +VALIDATE_UNRET_BEGIN +UNWIND_HINT_EMPTY .endm .macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 partial=0 signal=1
@@ -52,6 +53,11 @@ UNWIND_HINT_REGS base=\base offset=\offset partial=1 signal=\signal .endm +.macro UNWIND_HINT_IRET_ENTRY base=%rsp offset=0 signal=1 + VALIDATE_UNRET_BEGIN + UNWIND_HINT_IRET_REGS base=\base offset=\offset signal=\signal +.endm + .macro UNWIND_HINT_FUNC UNWIND_HINT sp_reg=ORC_REG_SP sp_offset=8 type=UNWIND_HINT_TYPE_FUNC .endm
arch/x86/kernel/head_64.S +0 -5
@@ -390,8 +390,6 @@ SYM_CODE_START_NOALIGN(vc_boot_ghcb) UNWIND_HINT_IRET_REGS offset=8 ENDBR - ANNOTATE_UNRET_END - /* Build pt_regs */ PUSH_AND_CLEAR_REGS
@@ -451,7 +449,6 @@ SYM_CODE_END(early_idt_handler_array) SYM_CODE_START_LOCAL(early_idt_handler_common) UNWIND_HINT_IRET_REGS offset=16 - ANNOTATE_UNRET_END /* * The stack is the hardware frame, an error code or zero, and the * vector number.
@@ -501,8 +498,6 @@ SYM_CODE_START_NOALIGN(vc_no_ghcb) UNWIND_HINT_IRET_REGS offset=8 ENDBR - ANNOTATE_UNRET_END - /* Build pt_regs */ PUSH_AND_CLEAR_REGS
include/linux/objtool.h +16 -0
@@ -124,6 +124,22 @@ .popsection .endm +/* + * Use objtool to validate the entry requirement that all code paths do + * VALIDATE_UNRET_END before RET. + * + * NOTE: The macro must be used at the beginning of a global symbol, otherwise + * it will be ignored. + */ +.macro VALIDATE_UNRET_BEGIN +#if defined(CONFIG_NOINSTR_VALIDATION ) && defined(CONFIG_CPU_UNRET_ENTRY ) +.Lhere_\@: + .pushsection .discard.validate_unret + .long .Lhere_\@ - . + .popsection +#endif +.endm + .macro REACHABLE .Lhere_\@: .pushsection .discard.reachable
include/linux/objtool_types.h +2 -3
@@ -42,8 +42,7 @@ struct unwind_hint {#define UNWIND_HINT_TYPE_REGS_PARTIAL 2/* The below hint types don't have corresponding ORC types */ #define UNWIND_HINT_TYPE_FUNC 3 -#define UNWIND_HINT_TYPE_ENTRY 4 -#define UNWIND_HINT_TYPE_SAVE 5 -#define UNWIND_HINT_TYPE_RESTORE 6 +#define UNWIND_HINT_TYPE_SAVE 4 +#define UNWIND_HINT_TYPE_RESTORE 5#endif /* _LINUX_OBJTOOL_TYPES_H */
tools/include/linux/objtool_types.h +2 -3
@@ -42,8 +42,7 @@ struct unwind_hint {#define UNWIND_HINT_TYPE_REGS_PARTIAL 2/* The below hint types don't have corresponding ORC types */ #define UNWIND_HINT_TYPE_FUNC 3 -#define UNWIND_HINT_TYPE_ENTRY 4 -#define UNWIND_HINT_TYPE_SAVE 5 -#define UNWIND_HINT_TYPE_RESTORE 6 +#define UNWIND_HINT_TYPE_SAVE 4 +#define UNWIND_HINT_TYPE_RESTORE 5#endif /* _LINUX_OBJTOOL_TYPES_H */
tools/objtool/check.c +45 -20
140 lines not on this page · raw message
tools/objtool/include/objtool/check.h +2 -2
@@ -61,7 +61,7 @@ struct instruction { restore : 1, retpoline_safe : 1, noendbr : 1, - entry : 1, + unret : 1, visited : 4, no_reloc : 1;/* 10 bit hole */
@@ -92,7 +92,7 @@ static inline struct symbol *insn_func(struct instruction *insn)#define VISITED_BRANCH 0x01#define VISITED_BRANCH_UACCESS 0x02#define VISITED_BRANCH_MASK 0x03 -#define VISITED_ENTRY 0x04 +#define VISITED_UNRET 0x04static inline bool is_static_jump (struct instruction *insn) {
Signature · 1 line
2.39.1
[tip: objtool/core] x86,objtool: Separate unret validation from unwind hints
The following commit has been merged into the objtool/core branch of tip:
The following commit has been merged into the objtool/core branch of tip:
Commit-ID: 4708ea14bef314fc901857eefd65678236a9f2d9 Gitweb: https://git.kernel.org/tip/4708ea14bef314fc901857eefd65678236a9f2d9 Author: Josh Poimboeuf <[email protected]> AuthorDate: Wed, 01 Mar 2023 07:13:11 -08:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Thu, 23 Mar 2023 23:18:58 +01:00
x86,objtool: Separate unret validation from unwind hints
The ENTRY unwind hint type is serving double duty as both an empty unwind hint and an unret validation annotation.
Unret validation is unrelated to unwinding. Separate it out into its own annotation.
--- arch/x86/entry/entry_64.S | 14 +++--- arch/x86/include/asm/nospec-branch.h | 8 +-- arch/x86/include/asm/unwind_hints.h | 8 ++- arch/x86/kernel/head_64.S | 5 +-- include/linux/objtool.h | 16 ++++++- include/linux/objtool_types.h | 5 +-- tools/include/linux/objtool_types.h | 5 +-- tools/objtool/check.c | 65 ++++++++++++++++++-------- tools/objtool/include/objtool/check.h | 4 +- 9 files changed, 85 insertions(+), 45 deletions(-)
arch/x86/entry/entry_64.S +7 -7
@@ -388,9 +388,9 @@ SYM_CODE_START(\asmsym) .if \vector == X86_TRAP_BP /* #BP advances %rip to the next instruction */ - UNWIND_HINT_IRET_REGS offset=\has_error_code*8 signal=0 + UNWIND_HINT_IRET_ENTRY offset=\has_error_code*8 signal=0 .else - UNWIND_HINT_IRET_REGS offset=\has_error_code*8 + UNWIND_HINT_IRET_ENTRY offset=\has_error_code*8 .endif ENDBR
@@ -461,7 +461,7 @@ SYM_CODE_END(\asmsym) */ .macro idtentry_mce_db vector asmsym cfunc SYM_CODE_START(\asmsym) - UNWIND_HINT_IRET_REGS + UNWIND_HINT_IRET_ENTRY ENDBR ASM_CLAC cld
@@ -518,7 +518,7 @@ SYM_CODE_END(\asmsym) */ .macro idtentry_vc vector asmsym cfunc SYM_CODE_START(\asmsym) - UNWIND_HINT_IRET_REGS + UNWIND_HINT_IRET_ENTRY ENDBR ASM_CLAC cld
@@ -582,7 +582,7 @@ SYM_CODE_END(\asmsym) */ .macro idtentry_df vector asmsym cfunc SYM_CODE_START(\asmsym) - UNWIND_HINT_IRET_REGS offset=8 + UNWIND_HINT_IRET_ENTRY offset=8 ENDBR ASM_CLAC cld
@@ -1107,7 +1107,7 @@ SYM_CODE_START(error_entry) FENCE_SWAPGS_KERNEL_ENTRY CALL_DEPTH_ACCOUNT leaq 8(%rsp), %rax /* return pt_regs pointer */ - ANNOTATE_UNRET_END + VALIDATE_UNRET_END RET .Lbstep_iret:
@@ -1153,7 +1153,7 @@ SYM_CODE_END(error_return) * when PAGE_TABLE_ISOLATION is in use. Do not clobber. */ SYM_CODE_START(asm_exc_nmi) - UNWIND_HINT_IRET_REGS + UNWIND_HINT_IRET_ENTRY ENDBR /*
arch/x86/include/asm/nospec-branch.h +4 -4
@@ -210,8 +210,8 @@* Abuse ANNOTATE_RETPOLINE_SAFE on a NOP to indicate UNRET_END, should * eventually turn into it's own annotation. */ -.macro ANNOTATE_UNRET_END -#ifdef CONFIG_DEBUG_ENTRY +.macro VALIDATE_UNRET_END +#if defined(CONFIG_NOINSTR_VALIDATION ) && defined(CONFIG_CPU_UNRET_ENTRY )ANNOTATE_RETPOLINE_SAFE nop#endif
@@ -286,7 +286,7 @@ .macro UNTRAIN_RET#if defined(CONFIG_CPU_UNRET_ENTRY ) || defined(CONFIG_CPU_IBPB_ENTRY ) || \ defined(CONFIG_CALL_DEPTH_TRACKING ) -ANNOTATE_UNRET_END +VALIDATE_UNRET_END ALTERNATIVE_3 "", \CALL_ZEN_UNTRAIN_RET ,X86_FEATURE_UNRET , \ "call entry_ibpb", X86_FEATURE_ENTRY_IBPB, \
@@ -297,7 +297,7 @@ .macro UNTRAIN_RET_FROM_CALL#if defined(CONFIG_CPU_UNRET_ENTRY ) || defined(CONFIG_CPU_IBPB_ENTRY ) || \ defined(CONFIG_CALL_DEPTH_TRACKING ) -ANNOTATE_UNRET_END +VALIDATE_UNRET_END ALTERNATIVE_3 "", \CALL_ZEN_UNTRAIN_RET ,X86_FEATURE_UNRET , \ "call entry_ibpb", X86_FEATURE_ENTRY_IBPB, \
arch/x86/include/asm/unwind_hints.h +7 -1
@@ -12,7 +12,8 @@ .endm .macro UNWIND_HINT_ENTRY - UNWIND_HINT type=UNWIND_HINT_TYPE_ENTRY end=1 +VALIDATE_UNRET_BEGIN +UNWIND_HINT_EMPTY .endm .macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 partial=0 signal=1
@@ -52,6 +53,11 @@ UNWIND_HINT_REGS base=\base offset=\offset partial=1 signal=\signal .endm +.macro UNWIND_HINT_IRET_ENTRY base=%rsp offset=0 signal=1 + VALIDATE_UNRET_BEGIN + UNWIND_HINT_IRET_REGS base=\base offset=\offset signal=\signal +.endm + .macro UNWIND_HINT_FUNC UNWIND_HINT sp_reg=ORC_REG_SP sp_offset=8 type=UNWIND_HINT_TYPE_FUNC .endm
arch/x86/kernel/head_64.S +0 -5
@@ -390,8 +390,6 @@ SYM_CODE_START_NOALIGN(vc_boot_ghcb) UNWIND_HINT_IRET_REGS offset=8 ENDBR - ANNOTATE_UNRET_END - /* Build pt_regs */ PUSH_AND_CLEAR_REGS
@@ -451,7 +449,6 @@ SYM_CODE_END(early_idt_handler_array) SYM_CODE_START_LOCAL(early_idt_handler_common) UNWIND_HINT_IRET_REGS offset=16 - ANNOTATE_UNRET_END /* * The stack is the hardware frame, an error code or zero, and the * vector number.
@@ -501,8 +498,6 @@ SYM_CODE_START_NOALIGN(vc_no_ghcb) UNWIND_HINT_IRET_REGS offset=8 ENDBR - ANNOTATE_UNRET_END - /* Build pt_regs */ PUSH_AND_CLEAR_REGS
include/linux/objtool.h +16 -0
@@ -124,6 +124,22 @@ .popsection .endm +/* + * Use objtool to validate the entry requirement that all code paths do + * VALIDATE_UNRET_END before RET. + * + * NOTE: The macro must be used at the beginning of a global symbol, otherwise + * it will be ignored. + */ +.macro VALIDATE_UNRET_BEGIN +#if defined(CONFIG_NOINSTR_VALIDATION ) && defined(CONFIG_CPU_UNRET_ENTRY ) +.Lhere_\@: + .pushsection .discard.validate_unret + .long .Lhere_\@ - . + .popsection +#endif +.endm + .macro REACHABLE .Lhere_\@: .pushsection .discard.reachable
include/linux/objtool_types.h +2 -3
@@ -42,8 +42,7 @@ struct unwind_hint {#define UNWIND_HINT_TYPE_REGS_PARTIAL 2/* The below hint types don't have corresponding ORC types */ #define UNWIND_HINT_TYPE_FUNC 3 -#define UNWIND_HINT_TYPE_ENTRY 4 -#define UNWIND_HINT_TYPE_SAVE 5 -#define UNWIND_HINT_TYPE_RESTORE 6 +#define UNWIND_HINT_TYPE_SAVE 4 +#define UNWIND_HINT_TYPE_RESTORE 5#endif /* _LINUX_OBJTOOL_TYPES_H */
tools/include/linux/objtool_types.h +2 -3
@@ -42,8 +42,7 @@ struct unwind_hint {#define UNWIND_HINT_TYPE_REGS_PARTIAL 2/* The below hint types don't have corresponding ORC types */ #define UNWIND_HINT_TYPE_FUNC 3 -#define UNWIND_HINT_TYPE_ENTRY 4 -#define UNWIND_HINT_TYPE_SAVE 5 -#define UNWIND_HINT_TYPE_RESTORE 6 +#define UNWIND_HINT_TYPE_SAVE 4 +#define UNWIND_HINT_TYPE_RESTORE 5#endif /* _LINUX_OBJTOOL_TYPES_H */
tools/objtool/check.c +45 -20
140 lines not on this page · raw message
tools/objtool/include/objtool/check.h +2 -2
@@ -61,7 +61,7 @@ struct instruction { restore : 1, retpoline_safe : 1, noendbr : 1, - entry : 1, + unret : 1, visited : 4, no_reloc : 1;/* 10 bit hole */
@@ -92,7 +92,7 @@ static inline struct symbol *insn_func(struct instruction *insn)#define VISITED_BRANCH 0x01#define VISITED_BRANCH_UACCESS 0x02#define VISITED_BRANCH_MASK 0x03 -#define VISITED_ENTRY 0x04 +#define VISITED_UNRET 0x04static inline bool is_static_jump (struct instruction *insn) {
Josh Poimboeuf
maintainerPATCH 6/6 x86,objtool: Split UNWIND_HINT_EMPTY in two
In reply to Josh PoimboeufMark reported that the ORC unwinder incorrectly marks an unwind as reliable when the unwind terminates prematurely in the dark corners of return_to_handler() due to lack of information about the next frame.
The problem is UNWIND_HINT_EMPTY is used in two different situations:
1) The end of the kernel stack unwind before hitting user entry, boot code, or fork entry
2) A blind spot in ORC coverage where the unwinder has to bail due to lack of information about the next frame
The ORC unwinder has no way to tell the difference between the two. When it encounters an undefined stack state with 'end=1', it blindly marks the stack reliable, which can break the livepatch consistency model.
Fix it by splitting UNWIND_HINT_EMPTY into UNWIND_HINT_UNDEFINED and UNWIND_HINT_END_OF_STACK.
--- .../livepatch/reliable-stacktrace.rst | 2 +- arch/x86/entry/entry_64.S | 12 ++++----- arch/x86/include/asm/orc_types.h | 14 +++++----- arch/x86/include/asm/unwind_hints.h | 12 ++++++--- arch/x86/kernel/ftrace_64.S | 2 +- arch/x86/kernel/head_64.S | 12 ++++----- arch/x86/kernel/relocate_kernel_64.S | 10 +++---- arch/x86/kernel/unwind_orc.c | 15 +++++------ arch/x86/lib/retpoline.S | 6 ++--- arch/x86/platform/pvh/head.S | 2 +- arch/x86/xen/xen-asm.S | 4 +-- arch/x86/xen/xen-head.S | 4 +-- include/linux/objtool.h | 10 +++---- include/linux/objtool_types.h | 27 ++++++++++++------- scripts/sorttable.h | 2 +- tools/arch/x86/include/asm/orc_types.h | 14 +++++----- tools/include/linux/objtool_types.h | 27 ++++++++++++------- tools/objtool/check.c | 2 +- tools/objtool/orc_dump.c | 8 ++++-- tools/objtool/orc_gen.c | 26 +++++++++--------- 20 files changed, 116 insertions(+), 95 deletions(-)
Documentation/livepatch/reliable-stacktrace.rst +1 -1
@@ -183,7 +183,7 @@ trampoline or return trampoline. For example, considering the x86_64 .. code-block:: none SYM_CODE_START(return_to_handler) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED subq $24, %rsp /* Save the return values */
arch/x86/entry/entry_64.S +6 -6
@@ -205,7 +205,7 @@ syscall_return_via_sysret: */ movq %rsp, %rdi movq PER_CPU_VAR(cpu_tss_rw + TSS_sp0), %rsp - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK pushq RSP-RDI(%rdi) /* RSP */ pushq (%rdi) /* RDI */
@@ -286,7 +286,7 @@ SYM_FUNC_END(__switch_to_asm) .pushsection .text, "ax" __FUNC_ALIGN SYM_CODE_START_NOALIGN(ret_from_fork) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR // copy_thread CALL_DEPTH_ACCOUNT movq %rax, %rdi
@@ -303,7 +303,7 @@ SYM_CODE_START_NOALIGN(ret_from_fork) 1: /* kernel thread */ - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK movq %r12, %rdi CALL_NOSPEC rbx /*
@@ -643,7 +643,7 @@ SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL) */ movq %rsp, %rdi movq PER_CPU_VAR(cpu_tss_rw + TSS_sp0), %rsp - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK /* Copy the IRET frame to the trampoline stack. */ pushq 6*8(%rdi) /* SS */
@@ -869,7 +869,7 @@ SYM_CODE_END(exc_xen_hypervisor_callback) */ __FUNC_ALIGN SYM_CODE_START_NOALIGN(xen_failsafe_callback) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ENDBR movl %ds, %ecx cmpw %cx, 0x10(%rsp)
@@ -1520,7 +1520,7 @@ SYM_CODE_END(asm_exc_nmi) * MSRs to fully disable 32-bit SYSCALL. */ SYM_CODE_START(ignore_sysret) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ENDBR mov $-ENOSYS, %eax sysretl
arch/x86/include/asm/orc_types.h +7 -7
@@ -39,9 +39,11 @@#define ORC_REG_SP_INDIRECT 9#define ORC_REG_MAX 15 -#define ORC_TYPE_CALL 0 -#define ORC_TYPE_REGS 1 -#define ORC_TYPE_REGS_PARTIAL 2 +#define ORC_TYPE_UNDEFINED 0 +#define ORC_TYPE_END_OF_STACK 1 +#define ORC_TYPE_CALL 2 +#define ORC_TYPE_REGS 3 +#define ORC_TYPE_REGS_PARTIAL 4#ifndef __ASSEMBLY__#include <asm/byteorder.h>
@@ -60,16 +62,14 @@ struct orc_entry {#if defined(__LITTLE_ENDIAN_BITFIELD) unsigned sp_reg:4; unsigned bp_reg:4; - unsigned type:2; + unsigned type:3; unsigned signal:1; - unsigned end:1;#elif defined(__BIG_ENDIAN_BITFIELD) unsigned bp_reg:4; unsigned sp_reg:4; unsigned unused:4; - unsigned end:1; unsigned signal:1; - unsigned type:2; + unsigned type:3;#endif } __packed;
arch/x86/include/asm/unwind_hints.h +8 -4
@@ -7,13 +7,17 @@#ifdef __ASSEMBLY__ -.macro UNWIND_HINT_EMPTY - UNWIND_HINT type=UNWIND_HINT_TYPE_CALL end=1 +.macro UNWIND_HINT_END_OF_STACK +UNWIND_HINT type=UNWIND_HINT_TYPE_END_OF_STACK +.endm + +.macro UNWIND_HINT_UNDEFINED + UNWIND_HINT type=UNWIND_HINT_TYPE_UNDEFINED .endm .macro UNWIND_HINT_ENTRY VALIDATE_UNRET_BEGIN -UNWIND_HINT_EMPTY +UNWIND_HINT_END_OF_STACK .endm .macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 partial=0 signal=1
@@ -73,7 +77,7 @@#else #define UNWIND_HINT_FUNC \ - UNWIND_HINT(UNWIND_HINT_TYPE_FUNC, ORC_REG_SP, 8, 0, 0) + UNWIND_HINT(UNWIND_HINT_TYPE_FUNC, ORC_REG_SP, 8, 0)#endif /* __ASSEMBLY__ */
arch/x86/kernel/ftrace_64.S +1 -1
@@ -340,7 +340,7 @@ STACK_FRAME_NON_STANDARD_FP(__fentry__) #ifdef CONFIG_FUNCTION_GRAPH_TRACER SYM_CODE_START(return_to_handler) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ANNOTATE_NOENDBR subq $16, %rsp
arch/x86/kernel/head_64.S +6 -6
@@ -42,7 +42,7 @@ L3_START_KERNEL = pud_index(__START_KERNEL_map) __HEAD .code64 SYM_CODE_START_NOALIGN(startup_64) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK /* * At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 0, * and someone has loaded an identity mapped page table
@@ -105,7 +105,7 @@ SYM_CODE_START_NOALIGN(startup_64) lretq .Lon_kernel_cs: - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK /* Sanitize CPU configuration */ call verify_cpu
@@ -127,7 +127,7 @@ SYM_CODE_START_NOALIGN(startup_64) SYM_CODE_END(startup_64) SYM_CODE_START(secondary_startup_64) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR /* * At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 0,
@@ -156,7 +156,7 @@ SYM_CODE_START(secondary_startup_64) * verify_cpu() above to make sure NX is enabled. */ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR /*
@@ -238,7 +238,7 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL) ANNOTATE_RETPOLINE_SAFE jmp *%rax 1: - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR // above /*
@@ -371,7 +371,7 @@ SYM_CODE_END(secondary_startup_64) */ SYM_CODE_START(start_cpu0) ANNOTATE_NOENDBR - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK movq initial_stack(%rip), %rsp jmp .Ljump_to_C_code SYM_CODE_END(start_cpu0)
arch/x86/kernel/relocate_kernel_64.S +5 -5
@@ -43,7 +43,7 @@ .code64 SYM_CODE_START_NOALIGN(relocate_range) SYM_CODE_START_NOALIGN(relocate_kernel) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR /* * %rdi indirection_page
@@ -113,7 +113,7 @@ SYM_CODE_START_NOALIGN(relocate_kernel) SYM_CODE_END(relocate_kernel) SYM_CODE_START_LOCAL_NOALIGN(identity_mapped) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK /* set return address to 0 if not preserving context */ pushq $0 /* store the start address on the stack */
@@ -231,7 +231,7 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped) SYM_CODE_END(identity_mapped) SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR // RET target, above movq RSP(%r8), %rsp movq CR4(%r8), %rax
@@ -256,8 +256,8 @@ SYM_CODE_END(virtual_mapped) /* Do the copies */ SYM_CODE_START_LOCAL_NOALIGN(swap_pages) - UNWIND_HINT_EMPTY - movq %rdi, %rcx /* Put the page_list in %rcx */ + UNWIND_HINT_END_OF_STACK + movq %rdi, %rcx /* Put the page_list in %rcx */ xorl %edi, %edi xorl %esi, %esi jmp 1f
arch/x86/kernel/unwind_orc.c +6 -9
@@ -158,7 +158,6 @@ static struct orc_entry orc_fp_entry = { .sp_offset = 16, .bp_reg = ORC_REG_PREV_SP, .bp_offset = -16, - .end = 0, };static struct orc_entry *orc_find (unsigned long ip)
@@ -250,13 +249,13 @@ static int orc_sort_cmp(const void *_a, const void *_b)return -1 ;/* -* The "weak" section terminator entries need to always be on the left +* The "weak" section terminator entries need to always be first * to ensure the lookup code skips them in favor of real entries. * These terminator entries exist to handle any gaps created by * whitelisted .o files which didn't get objtool generation. */ orc_a = cur_orc_table + (a - cur_orc_ip_table); -return orc_a->sp_reg ==ORC_REG_UNDEFINED && !orc_a->end ?-1 :1 ; +return orc_a->type ==ORC_TYPE_UNDEFINED ?-1 :1 ; } void unwind_module_init(struct module *mod, void *_orc_ip, size_t orc_ip_size,
@@ -474,14 +473,12 @@ bool unwind_next_frame(struct unwind_state *state)*/ orc = &orc_fp_entry; state->error = true; - } - -/* End-of-stack check for kernel threads: */ -if (orc->sp_reg ==ORC_REG_UNDEFINED ) { -if (!orc->end) + }else { +if (orc->type ==ORC_TYPE_UNDEFINED ) goto err; - goto the_end; +if (orc->type ==ORC_TYPE_END_OF_STACK ) + goto the_end; } state->signal = orc->signal;
arch/x86/lib/retpoline.S +3 -3
@@ -33,7 +33,7 @@ .align RETPOLINE_THUNK_SIZE SYM_INNER_LABEL(__x86_indirect_thunk_\reg, SYM_L_GLOBAL) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ANNOTATE_NOENDBR ALTERNATIVE_2 __stringify(RETPOLINE \reg), \
@@ -75,7 +75,7 @@ SYM_CODE_END(__x86_indirect_thunk_array) .align RETPOLINE_THUNK_SIZE SYM_INNER_LABEL(__x86_indirect_call_thunk_\reg, SYM_L_GLOBAL) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ANNOTATE_NOENDBR CALL_DEPTH_ACCOUNT
@@ -103,7 +103,7 @@ SYM_CODE_END(__x86_indirect_call_thunk_array) .align RETPOLINE_THUNK_SIZE SYM_INNER_LABEL(__x86_indirect_jump_thunk_\reg, SYM_L_GLOBAL) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ANNOTATE_NOENDBR POLINE \reg ANNOTATE_UNRET_SAFE
arch/x86/platform/pvh/head.S +1 -1
@@ -50,7 +50,7 @@ #define PVH_DS_SEL (PVH_GDT_ENTRY_DS * 8) SYM_CODE_START_LOCAL(pvh_start_xen) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK cld lgdt (_pa(gdt))
arch/x86/xen/xen-asm.S +2 -2
@@ -165,7 +165,7 @@ xen_pv_trap asm_exc_xen_hypervisor_callback SYM_CODE_START(xen_early_idt_handler_array) i = 0 .rept NUM_EXCEPTION_VECTORS - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ENDBR pop %rcx pop %r11
@@ -193,7 +193,7 @@ hypercall_iret = hypercall_page + __HYPERVISOR_iret * 32 * rsp->rax } */ SYM_CODE_START(xen_iret) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ANNOTATE_NOENDBR pushq $0 jmp hypercall_iret
arch/x86/xen/xen-head.S +2 -2
@@ -45,7 +45,7 @@ SYM_CODE_END(hypercall_page) #ifdef CONFIG_XEN_PV __INIT SYM_CODE_START(startup_xen) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR cld
@@ -71,7 +71,7 @@ SYM_CODE_END(startup_xen) #ifdef CONFIG_XEN_PV_SMP .pushsection .text SYM_CODE_START(asm_cpu_bringup_and_idle) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ENDBR call cpu_bringup_and_idle
include/linux/objtool.h +4 -6
@@ -10,7 +10,7 @@#ifndef __ASSEMBLY__ -#define UNWIND_HINT (type, sp_reg, sp_offset, signal, end) \ +#define UNWIND_HINT (type, sp_reg, sp_offset, signal) \ "987: \n\t" \ ".pushsection .discard.unwind_hints\n\t" \/* struct unwind_hint */ \
@@ -19,7 +19,6 @@ ".byte " __stringify(sp_reg) "\n\t" \ ".byte " __stringify(type) "\n\t" \ ".byte " __stringify(signal) "\n\t" \ - ".byte " __stringify(end) "\n\t" \".balign 4 \n\t" \".popsection\n\t"
@@ -91,7 +90,7 @@* the debuginfo as necessary. It will also warn if it sees any * inconsistencies. */ -.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0 +.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 .Lhere_\@: .pushsection .discard.unwind_hints/* struct unwind_hint */
@@ -100,7 +99,6 @@ .byte \sp_reg .byte \type .byte \signal - .byte \end .balign 4 .popsection .endm
@@ -153,14 +151,14 @@#ifndef __ASSEMBLY__ -#define UNWIND_HINT (type, sp_reg, sp_offset, signal, end) "\n\t" +#define UNWIND_HINT (type, sp_reg, sp_offset, signal) "\n\t"#define STACK_FRAME_NON_STANDARD (func)#define STACK_FRAME_NON_STANDARD_FP (func)#define ANNOTATE_NOENDBR #define ASM_REACHABLE #else #define ANNOTATE_INTRA_FUNCTION_CALL -.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0 +.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 .endm .macro STACK_FRAME_NON_STANDARD func:req .endm
include/linux/objtool_types.h +18 -9
@@ -16,12 +16,18 @@ struct unwind_hint {u8 sp_reg;u8 type; u8 signal; - u8 end; };#endif /* __ASSEMBLY__ */ /* +* UNWIND_HINT_TYPE_UNDEFINED: A blind spot in ORC coverage which can result in +* a truncated and unreliable stack unwind. +* +* UNWIND_HINT_TYPE_END_OF_STACK: The end of the kernel stack unwind before +* hitting user entry, boot code, or fork entry (when there are no pt_regs +* available). +* * UNWIND_HINT_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP * (the caller's SP right before it made the call). Used for all callable * functions, i.e. all C code and all callable asm functions.
@@ -32,17 +38,20 @@ struct unwind_hint {* UNWIND_HINT_TYPE_REGS_PARTIAL: Used in entry code to indicate that * sp_reg+sp_offset points to the iret return frame. * -* UNWIND_HINT_FUNC: Generate the unwind metadata of a callable function. +* UNWIND_HINT_TYPE_FUNC: Generate the unwind metadata of a callable function. * Useful for code which doesn't have an ELF function annotation. * -* UNWIND_HINT_ENTRY: machine entry without stack, SYSCALL/SYSENTER etc. +* UNWIND_HINT_TYPE_{SAVE,RESTORE}: Save the unwind metadata at a certain +* location so that it can be restored later. */ -#define UNWIND_HINT_TYPE_CALL 0 -#define UNWIND_HINT_TYPE_REGS 1 -#define UNWIND_HINT_TYPE_REGS_PARTIAL 2 +#define UNWIND_HINT_TYPE_UNDEFINED 0 +#define UNWIND_HINT_TYPE_END_OF_STACK 1 +#define UNWIND_HINT_TYPE_CALL 2 +#define UNWIND_HINT_TYPE_REGS 3 +#define UNWIND_HINT_TYPE_REGS_PARTIAL 4/* The below hint types don't have corresponding ORC types */ -#define UNWIND_HINT_TYPE_FUNC 3 -#define UNWIND_HINT_TYPE_SAVE 4 -#define UNWIND_HINT_TYPE_RESTORE 5 +#define UNWIND_HINT_TYPE_FUNC 5 +#define UNWIND_HINT_TYPE_SAVE 6 +#define UNWIND_HINT_TYPE_RESTORE 7#endif /* _LINUX_OBJTOOL_TYPES_H */
scripts/sorttable.h +1 -1
@@ -128,7 +128,7 @@ static int orc_sort_cmp(const void *_a, const void *_b)* whitelisted .o files which didn't get objtool generation. */ orc_a = g_orc_table + (a - g_orc_ip_table); -return orc_a->sp_reg ==ORC_REG_UNDEFINED && !orc_a->end ?-1 :1 ; +return orc_a->type ==ORC_TYPE_UNDEFINED ?-1 :1 ; }static void *sort_orctable (void *arg)
tools/arch/x86/include/asm/orc_types.h +7 -7
@@ -39,9 +39,11 @@#define ORC_REG_SP_INDIRECT 9#define ORC_REG_MAX 15 -#define ORC_TYPE_CALL 0 -#define ORC_TYPE_REGS 1 -#define ORC_TYPE_REGS_PARTIAL 2 +#define ORC_TYPE_UNDEFINED 0 +#define ORC_TYPE_END_OF_STACK 1 +#define ORC_TYPE_CALL 2 +#define ORC_TYPE_REGS 3 +#define ORC_TYPE_REGS_PARTIAL 4#ifndef __ASSEMBLY__#include <asm/byteorder.h>
@@ -60,16 +62,14 @@ struct orc_entry {#if defined(__LITTLE_ENDIAN_BITFIELD) unsigned sp_reg:4; unsigned bp_reg:4; - unsigned type:2; + unsigned type:3; unsigned signal:1; - unsigned end:1;#elif defined(__BIG_ENDIAN_BITFIELD) unsigned bp_reg:4; unsigned sp_reg:4; unsigned unused:4; - unsigned end:1; unsigned signal:1; - unsigned type:2; + unsigned type:3;#endif } __packed;
tools/include/linux/objtool_types.h +18 -9
@@ -16,12 +16,18 @@ struct unwind_hint {u8 sp_reg;u8 type; u8 signal; - u8 end; };#endif /* __ASSEMBLY__ */ /* +* UNWIND_HINT_TYPE_UNDEFINED: A blind spot in ORC coverage which can result in +* a truncated and unreliable stack unwind. +* +* UNWIND_HINT_TYPE_END_OF_STACK: The end of the kernel stack unwind before +* hitting user entry, boot code, or fork entry (when there are no pt_regs +* available). +* * UNWIND_HINT_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP * (the caller's SP right before it made the call). Used for all callable * functions, i.e. all C code and all callable asm functions.
@@ -32,17 +38,20 @@ struct unwind_hint {* UNWIND_HINT_TYPE_REGS_PARTIAL: Used in entry code to indicate that * sp_reg+sp_offset points to the iret return frame. * -* UNWIND_HINT_FUNC: Generate the unwind metadata of a callable function. +* UNWIND_HINT_TYPE_FUNC: Generate the unwind metadata of a callable function. * Useful for code which doesn't have an ELF function annotation. * -* UNWIND_HINT_ENTRY: machine entry without stack, SYSCALL/SYSENTER etc. +* UNWIND_HINT_TYPE_{SAVE,RESTORE}: Save the unwind metadata at a certain +* location so that it can be restored later. */ -#define UNWIND_HINT_TYPE_CALL 0 -#define UNWIND_HINT_TYPE_REGS 1 -#define UNWIND_HINT_TYPE_REGS_PARTIAL 2 +#define UNWIND_HINT_TYPE_UNDEFINED 0 +#define UNWIND_HINT_TYPE_END_OF_STACK 1 +#define UNWIND_HINT_TYPE_CALL 2 +#define UNWIND_HINT_TYPE_REGS 3 +#define UNWIND_HINT_TYPE_REGS_PARTIAL 4/* The below hint types don't have corresponding ORC types */ -#define UNWIND_HINT_TYPE_FUNC 3 -#define UNWIND_HINT_TYPE_SAVE 4 -#define UNWIND_HINT_TYPE_RESTORE 5 +#define UNWIND_HINT_TYPE_FUNC 5 +#define UNWIND_HINT_TYPE_SAVE 6 +#define UNWIND_HINT_TYPE_RESTORE 7#endif /* _LINUX_OBJTOOL_TYPES_H */
tools/objtool/check.c +1 -1
@@ -2240,6 +2240,7 @@ static void set_func_state(struct cfi_state *state)memcpy (&state->regs, &initial_func_cfi.regs,CFI_NUM_REGS *sizeof (struct cfi_reg )); state->stack_size = initial_func_cfi.cfa.offset; + state->type =UNWIND_HINT_TYPE_CALL ; }static int read_unwind_hints (struct objtool_file *file)
@@ -2324,7 +2325,6 @@ static int read_unwind_hints(struct objtool_file *file) cfi.cfa.offset =bswap_if_needed (file->elf, hint->sp_offset); cfi.type = hint->type; cfi.signal = hint->signal; - cfi.end = hint->end; insn->cfi =cfi_hash_find_or_add (&cfi); }
tools/objtool/orc_dump.c +6 -2
@@ -38,6 +38,10 @@ static const char *reg_name(unsigned int reg)static const char *orc_type_name (unsigned int type) {switch (type) { +case ORC_TYPE_UNDEFINED : +return "(und)" ; +case ORC_TYPE_END_OF_STACK : +return "end" ;case ORC_TYPE_CALL :return "call" ;case ORC_TYPE_REGS :
@@ -201,6 +205,7 @@ int orc_dump(const char *_objname)printf ("%llx:" , (unsigned long long )(orc_ip_addr + (i *sizeof (int )) + orc_ip[i])); } +printf ("type:%s" ,orc_type_name (orc[i].type));printf (" sp:" );
@@ -210,8 +215,7 @@ int orc_dump(const char *_objname)print_reg (orc[i].bp_reg,bswap_if_needed (&dummy_elf, orc[i].bp_offset)); -printf (" type:%s signal:%d end:%d\n" , -orc_type_name (orc[i].type), orc[i].signal, orc[i].end); +printf (" signal:%d\n" , orc[i].signal); }elf_end (elf);
tools/objtool/orc_gen.c +13 -13
@@ -21,12 +21,22 @@ static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi,memset (orc,0 ,sizeof (*orc));if (!cfi) { - orc->end =0 ; - orc->sp_reg =ORC_REG_UNDEFINED ; +/* +* This is usually either unreachable nops/traps (which don't +* trigger unreachable instruction warnings), or +* STACK_FRAME_NON_STANDARD functions. +*/ + orc->type =ORC_TYPE_UNDEFINED ;return 0 ; }switch (cfi->type) { +case UNWIND_HINT_TYPE_UNDEFINED : + orc->type =ORC_TYPE_UNDEFINED ; +return 0 ; +case UNWIND_HINT_TYPE_END_OF_STACK : + orc->type =ORC_TYPE_END_OF_STACK ; +return 0 ;case UNWIND_HINT_TYPE_CALL : orc->type =ORC_TYPE_CALL ;break ;
@@ -42,14 +52,8 @@ static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi,return -1 ; } - orc->end = cfi->end; orc->signal = cfi->signal; -if (cfi->cfa.base ==CFI_UNDEFINED ) { - orc->sp_reg =ORC_REG_UNDEFINED ; -return 0 ; - } -switch (cfi->cfa.base) {case CFI_SP : orc->sp_reg =ORC_REG_SP ;
@@ -163,11 +167,7 @@ int orc_create(struct objtool_file *file)struct orc_list_entry *entry;struct list_head orc_list; -struct orc_entry null = { - .sp_reg =ORC_REG_UNDEFINED , - .bp_reg =ORC_REG_UNDEFINED , - .type =ORC_TYPE_CALL , - }; +struct orc_entry null = { .type =ORC_TYPE_UNDEFINED };/* Build a deduplicated list of ORC entries: */ INIT_LIST_HEAD (&orc_list);
Signature · 1 line
2.39.1
arch/x86/kernel/ftrace_64.S STACK_FRAME_NON_STANDARD_FP(__fentry__) · line 346
Quoted 13 lines · On Wed, 1 Mar 2023 07:13:12 -0800 Josh Poimboeuf <[email protected]> wrote:
arch/x86/kernel/ftrace_64.S +1
-1@@ -340,7 +340,7 @@ STACK_FRAME_NON_STANDARD_FP(__fentry__) #ifdef CONFIG_FUNCTION_GRAPH_TRACER SYM_CODE_START(return_to_handler) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ANNOTATE_NOENDBR subq $16, %rsp
-- Steve
The following commit has been merged into the objtool/core branch of tip:
The following commit has been merged into the objtool/core branch of tip:
Commit-ID: fb799447ae2974a07907906dff5bd4b9e47b7123 Gitweb: https://git.kernel.org/tip/fb799447ae2974a07907906dff5bd4b9e47b7123 Author: Josh Poimboeuf <[email protected]> AuthorDate: Wed, 01 Mar 2023 07:13:12 -08:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Thu, 23 Mar 2023 23:18:58 +01:00
x86,objtool: Split UNWIND_HINT_EMPTY in two
Mark reported that the ORC unwinder incorrectly marks an unwind as reliable when the unwind terminates prematurely in the dark corners of return_to_handler() due to lack of information about the next frame.
The problem is UNWIND_HINT_EMPTY is used in two different situations:
1) The end of the kernel stack unwind before hitting user entry, boot code, or fork entry
2) A blind spot in ORC coverage where the unwinder has to bail due to lack of information about the next frame
The ORC unwinder has no way to tell the difference between the two. When it encounters an undefined stack state with 'end=1', it blindly marks the stack reliable, which can break the livepatch consistency model.
Fix it by splitting UNWIND_HINT_EMPTY into UNWIND_HINT_UNDEFINED and UNWIND_HINT_END_OF_STACK.
--- Documentation/livepatch/reliable-stacktrace.rst | 2 +- arch/x86/entry/entry_64.S | 12 +++---- arch/x86/include/asm/orc_types.h | 14 ++++---- arch/x86/include/asm/unwind_hints.h | 12 ++++--- arch/x86/kernel/ftrace_64.S | 2 +- arch/x86/kernel/head_64.S | 12 +++---- arch/x86/kernel/relocate_kernel_64.S | 10 +++--- arch/x86/kernel/unwind_orc.c | 15 +++------ arch/x86/lib/retpoline.S | 6 ++-- arch/x86/platform/pvh/head.S | 2 +- arch/x86/xen/xen-asm.S | 4 +- arch/x86/xen/xen-head.S | 4 +- include/linux/objtool.h | 10 ++---- include/linux/objtool_types.h | 27 ++++++++++------ scripts/sorttable.h | 2 +- tools/arch/x86/include/asm/orc_types.h | 14 ++++---- tools/include/linux/objtool_types.h | 27 ++++++++++------ tools/objtool/check.c | 2 +- tools/objtool/orc_dump.c | 8 +++-- tools/objtool/orc_gen.c | 26 +++++++-------- 20 files changed, 116 insertions(+), 95 deletions(-)
Documentation/livepatch/reliable-stacktrace.rst +1 -1
@@ -183,7 +183,7 @@ trampoline or return trampoline. For example, considering the x86_64 .. code-block:: none SYM_CODE_START(return_to_handler) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED subq $24, %rsp /* Save the return values */
arch/x86/entry/entry_64.S +6 -6
@@ -205,7 +205,7 @@ syscall_return_via_sysret: */ movq %rsp, %rdi movq PER_CPU_VAR(cpu_tss_rw + TSS_sp0), %rsp - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK pushq RSP-RDI(%rdi) /* RSP */ pushq (%rdi) /* RDI */
@@ -286,7 +286,7 @@ SYM_FUNC_END(__switch_to_asm) .pushsection .text, "ax" __FUNC_ALIGN SYM_CODE_START_NOALIGN(ret_from_fork) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR // copy_thread CALL_DEPTH_ACCOUNT movq %rax, %rdi
@@ -303,7 +303,7 @@ SYM_CODE_START_NOALIGN(ret_from_fork) 1: /* kernel thread */ - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK movq %r12, %rdi CALL_NOSPEC rbx /*
@@ -643,7 +643,7 @@ SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL) */ movq %rsp, %rdi movq PER_CPU_VAR(cpu_tss_rw + TSS_sp0), %rsp - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK /* Copy the IRET frame to the trampoline stack. */ pushq 6*8(%rdi) /* SS */
@@ -869,7 +869,7 @@ SYM_CODE_END(exc_xen_hypervisor_callback) */ __FUNC_ALIGN SYM_CODE_START_NOALIGN(xen_failsafe_callback) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ENDBR movl %ds, %ecx cmpw %cx, 0x10(%rsp)
@@ -1520,7 +1520,7 @@ SYM_CODE_END(asm_exc_nmi) * MSRs to fully disable 32-bit SYSCALL. */ SYM_CODE_START(ignore_sysret) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ENDBR mov $-ENOSYS, %eax sysretl
arch/x86/include/asm/orc_types.h +7 -7
@@ -39,9 +39,11 @@#define ORC_REG_SP_INDIRECT 9#define ORC_REG_MAX 15 -#define ORC_TYPE_CALL 0 -#define ORC_TYPE_REGS 1 -#define ORC_TYPE_REGS_PARTIAL 2 +#define ORC_TYPE_UNDEFINED 0 +#define ORC_TYPE_END_OF_STACK 1 +#define ORC_TYPE_CALL 2 +#define ORC_TYPE_REGS 3 +#define ORC_TYPE_REGS_PARTIAL 4#ifndef __ASSEMBLY__#include <asm/byteorder.h>
@@ -60,16 +62,14 @@ struct orc_entry {#if defined(__LITTLE_ENDIAN_BITFIELD) unsigned sp_reg:4; unsigned bp_reg:4; - unsigned type:2; + unsigned type:3; unsigned signal:1; - unsigned end:1;#elif defined(__BIG_ENDIAN_BITFIELD) unsigned bp_reg:4; unsigned sp_reg:4; unsigned unused:4; - unsigned end:1; unsigned signal:1; - unsigned type:2; + unsigned type:3;#endif } __packed;
arch/x86/include/asm/unwind_hints.h +8 -4
@@ -7,13 +7,17 @@#ifdef __ASSEMBLY__ -.macro UNWIND_HINT_EMPTY - UNWIND_HINT type=UNWIND_HINT_TYPE_CALL end=1 +.macro UNWIND_HINT_END_OF_STACK +UNWIND_HINT type=UNWIND_HINT_TYPE_END_OF_STACK +.endm + +.macro UNWIND_HINT_UNDEFINED + UNWIND_HINT type=UNWIND_HINT_TYPE_UNDEFINED .endm .macro UNWIND_HINT_ENTRY VALIDATE_UNRET_BEGIN -UNWIND_HINT_EMPTY +UNWIND_HINT_END_OF_STACK .endm .macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 partial=0 signal=1
@@ -73,7 +77,7 @@#else #define UNWIND_HINT_FUNC \ - UNWIND_HINT(UNWIND_HINT_TYPE_FUNC, ORC_REG_SP, 8, 0, 0) + UNWIND_HINT(UNWIND_HINT_TYPE_FUNC, ORC_REG_SP, 8, 0)#endif /* __ASSEMBLY__ */
arch/x86/kernel/ftrace_64.S +1 -1
@@ -340,7 +340,7 @@ STACK_FRAME_NON_STANDARD_FP(__fentry__) #ifdef CONFIG_FUNCTION_GRAPH_TRACER SYM_CODE_START(return_to_handler) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ANNOTATE_NOENDBR subq $16, %rsp
arch/x86/kernel/head_64.S +6 -6
@@ -42,7 +42,7 @@ L3_START_KERNEL = pud_index(__START_KERNEL_map) __HEAD .code64 SYM_CODE_START_NOALIGN(startup_64) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK /* * At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 0, * and someone has loaded an identity mapped page table
@@ -105,7 +105,7 @@ SYM_CODE_START_NOALIGN(startup_64) lretq .Lon_kernel_cs: - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK /* Sanitize CPU configuration */ call verify_cpu
@@ -127,7 +127,7 @@ SYM_CODE_START_NOALIGN(startup_64) SYM_CODE_END(startup_64) SYM_CODE_START(secondary_startup_64) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR /* * At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 0,
@@ -156,7 +156,7 @@ SYM_CODE_START(secondary_startup_64) * verify_cpu() above to make sure NX is enabled. */ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR /*
@@ -238,7 +238,7 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL) ANNOTATE_RETPOLINE_SAFE jmp *%rax 1: - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR // above /*
@@ -371,7 +371,7 @@ SYM_CODE_END(secondary_startup_64) */ SYM_CODE_START(start_cpu0) ANNOTATE_NOENDBR - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK movq initial_stack(%rip), %rsp jmp .Ljump_to_C_code SYM_CODE_END(start_cpu0)
arch/x86/kernel/relocate_kernel_64.S +5 -5
@@ -43,7 +43,7 @@ .code64 SYM_CODE_START_NOALIGN(relocate_range) SYM_CODE_START_NOALIGN(relocate_kernel) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR /* * %rdi indirection_page
@@ -113,7 +113,7 @@ SYM_CODE_START_NOALIGN(relocate_kernel) SYM_CODE_END(relocate_kernel) SYM_CODE_START_LOCAL_NOALIGN(identity_mapped) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK /* set return address to 0 if not preserving context */ pushq $0 /* store the start address on the stack */
@@ -231,7 +231,7 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped) SYM_CODE_END(identity_mapped) SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR // RET target, above movq RSP(%r8), %rsp movq CR4(%r8), %rax
@@ -256,8 +256,8 @@ SYM_CODE_END(virtual_mapped) /* Do the copies */ SYM_CODE_START_LOCAL_NOALIGN(swap_pages) - UNWIND_HINT_EMPTY - movq %rdi, %rcx /* Put the page_list in %rcx */ + UNWIND_HINT_END_OF_STACK + movq %rdi, %rcx /* Put the page_list in %rcx */ xorl %edi, %edi xorl %esi, %esi jmp 1f
arch/x86/kernel/unwind_orc.c +6 -9
@@ -158,7 +158,6 @@ static struct orc_entry orc_fp_entry = { .sp_offset = 16, .bp_reg = ORC_REG_PREV_SP, .bp_offset = -16, - .end = 0, };static struct orc_entry *orc_find (unsigned long ip)
@@ -250,13 +249,13 @@ static int orc_sort_cmp(const void *_a, const void *_b)return -1 ;/* -* The "weak" section terminator entries need to always be on the left +* The "weak" section terminator entries need to always be first * to ensure the lookup code skips them in favor of real entries. * These terminator entries exist to handle any gaps created by * whitelisted .o files which didn't get objtool generation. */ orc_a = cur_orc_table + (a - cur_orc_ip_table); -return orc_a->sp_reg ==ORC_REG_UNDEFINED && !orc_a->end ?-1 :1 ; +return orc_a->type ==ORC_TYPE_UNDEFINED ?-1 :1 ; } void unwind_module_init(struct module *mod, void *_orc_ip, size_t orc_ip_size,
@@ -474,14 +473,12 @@ bool unwind_next_frame(struct unwind_state *state)*/ orc = &orc_fp_entry; state->error = true; - } - -/* End-of-stack check for kernel threads: */ -if (orc->sp_reg ==ORC_REG_UNDEFINED ) { -if (!orc->end) + }else { +if (orc->type ==ORC_TYPE_UNDEFINED ) goto err; - goto the_end; +if (orc->type ==ORC_TYPE_END_OF_STACK ) + goto the_end; } state->signal = orc->signal;
arch/x86/lib/retpoline.S +3 -3
@@ -33,7 +33,7 @@ .align RETPOLINE_THUNK_SIZE SYM_INNER_LABEL(__x86_indirect_thunk_\reg, SYM_L_GLOBAL) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ANNOTATE_NOENDBR ALTERNATIVE_2 __stringify(RETPOLINE \reg), \
@@ -75,7 +75,7 @@ SYM_CODE_END(__x86_indirect_thunk_array) .align RETPOLINE_THUNK_SIZE SYM_INNER_LABEL(__x86_indirect_call_thunk_\reg, SYM_L_GLOBAL) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ANNOTATE_NOENDBR CALL_DEPTH_ACCOUNT
@@ -103,7 +103,7 @@ SYM_CODE_END(__x86_indirect_call_thunk_array) .align RETPOLINE_THUNK_SIZE SYM_INNER_LABEL(__x86_indirect_jump_thunk_\reg, SYM_L_GLOBAL) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ANNOTATE_NOENDBR POLINE \reg ANNOTATE_UNRET_SAFE
arch/x86/platform/pvh/head.S +1 -1
@@ -50,7 +50,7 @@ #define PVH_DS_SEL (PVH_GDT_ENTRY_DS * 8) SYM_CODE_START_LOCAL(pvh_start_xen) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK cld lgdt (_pa(gdt))
arch/x86/xen/xen-asm.S +2 -2
@@ -165,7 +165,7 @@ xen_pv_trap asm_exc_xen_hypervisor_callback SYM_CODE_START(xen_early_idt_handler_array) i = 0 .rept NUM_EXCEPTION_VECTORS - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ENDBR pop %rcx pop %r11
@@ -193,7 +193,7 @@ hypercall_iret = hypercall_page + __HYPERVISOR_iret * 32 * rsp->rax } */ SYM_CODE_START(xen_iret) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ANNOTATE_NOENDBR pushq $0 jmp hypercall_iret
arch/x86/xen/xen-head.S +2 -2
@@ -45,7 +45,7 @@ SYM_CODE_END(hypercall_page) #ifdef CONFIG_XEN_PV __INIT SYM_CODE_START(startup_xen) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR cld
@@ -71,7 +71,7 @@ SYM_CODE_END(startup_xen) #ifdef CONFIG_XEN_PV_SMP .pushsection .text SYM_CODE_START(asm_cpu_bringup_and_idle) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ENDBR call cpu_bringup_and_idle
include/linux/objtool.h +4 -6
@@ -10,7 +10,7 @@#ifndef __ASSEMBLY__ -#define UNWIND_HINT (type, sp_reg, sp_offset, signal, end) \ +#define UNWIND_HINT (type, sp_reg, sp_offset, signal) \ "987: \n\t" \ ".pushsection .discard.unwind_hints\n\t" \/* struct unwind_hint */ \
@@ -19,7 +19,6 @@ ".byte " __stringify(sp_reg) "\n\t" \ ".byte " __stringify(type) "\n\t" \ ".byte " __stringify(signal) "\n\t" \ - ".byte " __stringify(end) "\n\t" \".balign 4 \n\t" \".popsection\n\t"
@@ -91,7 +90,7 @@* the debuginfo as necessary. It will also warn if it sees any * inconsistencies. */ -.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0 +.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 .Lhere_\@: .pushsection .discard.unwind_hints/* struct unwind_hint */
@@ -100,7 +99,6 @@ .byte \sp_reg .byte \type .byte \signal - .byte \end .balign 4 .popsection .endm
@@ -153,14 +151,14 @@#ifndef __ASSEMBLY__ -#define UNWIND_HINT (type, sp_reg, sp_offset, signal, end) "\n\t" +#define UNWIND_HINT (type, sp_reg, sp_offset, signal) "\n\t"#define STACK_FRAME_NON_STANDARD (func)#define STACK_FRAME_NON_STANDARD_FP (func)#define ANNOTATE_NOENDBR #define ASM_REACHABLE #else #define ANNOTATE_INTRA_FUNCTION_CALL -.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0 +.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 .endm .macro STACK_FRAME_NON_STANDARD func:req .endm
include/linux/objtool_types.h +18 -9
@@ -16,12 +16,18 @@ struct unwind_hint {u8 sp_reg;u8 type; u8 signal; - u8 end; };#endif /* __ASSEMBLY__ */ /* +* UNWIND_HINT_TYPE_UNDEFINED: A blind spot in ORC coverage which can result in +* a truncated and unreliable stack unwind. +* +* UNWIND_HINT_TYPE_END_OF_STACK: The end of the kernel stack unwind before +* hitting user entry, boot code, or fork entry (when there are no pt_regs +* available). +* * UNWIND_HINT_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP * (the caller's SP right before it made the call). Used for all callable * functions, i.e. all C code and all callable asm functions.
@@ -32,17 +38,20 @@ struct unwind_hint {* UNWIND_HINT_TYPE_REGS_PARTIAL: Used in entry code to indicate that * sp_reg+sp_offset points to the iret return frame. * -* UNWIND_HINT_FUNC: Generate the unwind metadata of a callable function. +* UNWIND_HINT_TYPE_FUNC: Generate the unwind metadata of a callable function. * Useful for code which doesn't have an ELF function annotation. * -* UNWIND_HINT_ENTRY: machine entry without stack, SYSCALL/SYSENTER etc. +* UNWIND_HINT_TYPE_{SAVE,RESTORE}: Save the unwind metadata at a certain +* location so that it can be restored later. */ -#define UNWIND_HINT_TYPE_CALL 0 -#define UNWIND_HINT_TYPE_REGS 1 -#define UNWIND_HINT_TYPE_REGS_PARTIAL 2 +#define UNWIND_HINT_TYPE_UNDEFINED 0 +#define UNWIND_HINT_TYPE_END_OF_STACK 1 +#define UNWIND_HINT_TYPE_CALL 2 +#define UNWIND_HINT_TYPE_REGS 3 +#define UNWIND_HINT_TYPE_REGS_PARTIAL 4/* The below hint types don't have corresponding ORC types */ -#define UNWIND_HINT_TYPE_FUNC 3 -#define UNWIND_HINT_TYPE_SAVE 4 -#define UNWIND_HINT_TYPE_RESTORE 5 +#define UNWIND_HINT_TYPE_FUNC 5 +#define UNWIND_HINT_TYPE_SAVE 6 +#define UNWIND_HINT_TYPE_RESTORE 7#endif /* _LINUX_OBJTOOL_TYPES_H */
scripts/sorttable.h +1 -1
@@ -128,7 +128,7 @@ static int orc_sort_cmp(const void *_a, const void *_b)* whitelisted .o files which didn't get objtool generation. */ orc_a = g_orc_table + (a - g_orc_ip_table); -return orc_a->sp_reg ==ORC_REG_UNDEFINED && !orc_a->end ?-1 :1 ; +return orc_a->type ==ORC_TYPE_UNDEFINED ?-1 :1 ; }static void *sort_orctable (void *arg)
tools/arch/x86/include/asm/orc_types.h +7 -7
@@ -39,9 +39,11 @@#define ORC_REG_SP_INDIRECT 9#define ORC_REG_MAX 15 -#define ORC_TYPE_CALL 0 -#define ORC_TYPE_REGS 1 -#define ORC_TYPE_REGS_PARTIAL 2 +#define ORC_TYPE_UNDEFINED 0 +#define ORC_TYPE_END_OF_STACK 1 +#define ORC_TYPE_CALL 2 +#define ORC_TYPE_REGS 3 +#define ORC_TYPE_REGS_PARTIAL 4#ifndef __ASSEMBLY__#include <asm/byteorder.h>
@@ -60,16 +62,14 @@ struct orc_entry {#if defined(__LITTLE_ENDIAN_BITFIELD) unsigned sp_reg:4; unsigned bp_reg:4; - unsigned type:2; + unsigned type:3; unsigned signal:1; - unsigned end:1;#elif defined(__BIG_ENDIAN_BITFIELD) unsigned bp_reg:4; unsigned sp_reg:4; unsigned unused:4; - unsigned end:1; unsigned signal:1; - unsigned type:2; + unsigned type:3;#endif } __packed;
tools/include/linux/objtool_types.h +18 -9
@@ -16,12 +16,18 @@ struct unwind_hint {u8 sp_reg;u8 type; u8 signal; - u8 end; };#endif /* __ASSEMBLY__ */ /* +* UNWIND_HINT_TYPE_UNDEFINED: A blind spot in ORC coverage which can result in +* a truncated and unreliable stack unwind. +* +* UNWIND_HINT_TYPE_END_OF_STACK: The end of the kernel stack unwind before +* hitting user entry, boot code, or fork entry (when there are no pt_regs +* available). +* * UNWIND_HINT_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP * (the caller's SP right before it made the call). Used for all callable * functions, i.e. all C code and all callable asm functions.
@@ -32,17 +38,20 @@ struct unwind_hint {* UNWIND_HINT_TYPE_REGS_PARTIAL: Used in entry code to indicate that * sp_reg+sp_offset points to the iret return frame. * -* UNWIND_HINT_FUNC: Generate the unwind metadata of a callable function. +* UNWIND_HINT_TYPE_FUNC: Generate the unwind metadata of a callable function. * Useful for code which doesn't have an ELF function annotation. * -* UNWIND_HINT_ENTRY: machine entry without stack, SYSCALL/SYSENTER etc. +* UNWIND_HINT_TYPE_{SAVE,RESTORE}: Save the unwind metadata at a certain +* location so that it can be restored later. */ -#define UNWIND_HINT_TYPE_CALL 0 -#define UNWIND_HINT_TYPE_REGS 1 -#define UNWIND_HINT_TYPE_REGS_PARTIAL 2 +#define UNWIND_HINT_TYPE_UNDEFINED 0 +#define UNWIND_HINT_TYPE_END_OF_STACK 1 +#define UNWIND_HINT_TYPE_CALL 2 +#define UNWIND_HINT_TYPE_REGS 3 +#define UNWIND_HINT_TYPE_REGS_PARTIAL 4/* The below hint types don't have corresponding ORC types */ -#define UNWIND_HINT_TYPE_FUNC 3 -#define UNWIND_HINT_TYPE_SAVE 4 -#define UNWIND_HINT_TYPE_RESTORE 5 +#define UNWIND_HINT_TYPE_FUNC 5 +#define UNWIND_HINT_TYPE_SAVE 6 +#define UNWIND_HINT_TYPE_RESTORE 7#endif /* _LINUX_OBJTOOL_TYPES_H */
tools/objtool/check.c +1 -1
@@ -2243,6 +2243,7 @@ static void set_func_state(struct cfi_state *state)memcpy (&state->regs, &initial_func_cfi.regs,CFI_NUM_REGS *sizeof (struct cfi_reg )); state->stack_size = initial_func_cfi.cfa.offset; + state->type =UNWIND_HINT_TYPE_CALL ; }static int read_unwind_hints (struct objtool_file *file)
@@ -2327,7 +2328,6 @@ static int read_unwind_hints(struct objtool_file *file) cfi.cfa.offset =bswap_if_needed (file->elf, hint->sp_offset); cfi.type = hint->type; cfi.signal = hint->signal; - cfi.end = hint->end; insn->cfi =cfi_hash_find_or_add (&cfi); }
tools/objtool/orc_dump.c +6 -2
@@ -38,6 +38,10 @@ static const char *reg_name(unsigned int reg)static const char *orc_type_name (unsigned int type) {switch (type) { +case ORC_TYPE_UNDEFINED : +return "(und)" ; +case ORC_TYPE_END_OF_STACK : +return "end" ;case ORC_TYPE_CALL :return "call" ;case ORC_TYPE_REGS :
@@ -201,6 +205,7 @@ int orc_dump(const char *_objname)printf ("%llx:" , (unsigned long long )(orc_ip_addr + (i *sizeof (int )) + orc_ip[i])); } +printf ("type:%s" ,orc_type_name (orc[i].type));printf (" sp:" );
@@ -210,8 +215,7 @@ int orc_dump(const char *_objname)print_reg (orc[i].bp_reg,bswap_if_needed (&dummy_elf, orc[i].bp_offset)); -printf (" type:%s signal:%d end:%d\n" , -orc_type_name (orc[i].type), orc[i].signal, orc[i].end); +printf (" signal:%d\n" , orc[i].signal); }elf_end (elf);
tools/objtool/orc_gen.c +13 -13
@@ -21,12 +21,22 @@ static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi,memset (orc,0 ,sizeof (*orc));if (!cfi) { - orc->end =0 ; - orc->sp_reg =ORC_REG_UNDEFINED ; +/* +* This is usually either unreachable nops/traps (which don't +* trigger unreachable instruction warnings), or +* STACK_FRAME_NON_STANDARD functions. +*/ + orc->type =ORC_TYPE_UNDEFINED ;return 0 ; }switch (cfi->type) { +case UNWIND_HINT_TYPE_UNDEFINED : + orc->type =ORC_TYPE_UNDEFINED ; +return 0 ; +case UNWIND_HINT_TYPE_END_OF_STACK : + orc->type =ORC_TYPE_END_OF_STACK ; +return 0 ;case UNWIND_HINT_TYPE_CALL : orc->type =ORC_TYPE_CALL ;break ;
@@ -42,14 +52,8 @@ static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi,return -1 ; } - orc->end = cfi->end; orc->signal = cfi->signal; -if (cfi->cfa.base ==CFI_UNDEFINED ) { - orc->sp_reg =ORC_REG_UNDEFINED ; -return 0 ; - } -switch (cfi->cfa.base) {case CFI_SP : orc->sp_reg =ORC_REG_SP ;
@@ -163,11 +167,7 @@ int orc_create(struct objtool_file *file)struct orc_list_entry *entry;struct list_head orc_list; -struct orc_entry null = { - .sp_reg =ORC_REG_UNDEFINED , - .bp_reg =ORC_REG_UNDEFINED , - .type =ORC_TYPE_CALL , - }; +struct orc_entry null = { .type =ORC_TYPE_UNDEFINED };/* Build a deduplicated list of ORC entries: */ INIT_LIST_HEAD (&orc_list);
Quoted 11 lines · Josh Poimboeuf
Based on tip/objtool/core.
Mark reported that the ORC unwinder incorrectly marks an unwind as reliable when the unwind terminates prematurely in the dark corners of
return_to_handler()due to lack of information about the next frame.The problem is
UNWIND_HINT_EMPTYis used in two different situations:
end-of-stack marker and undefined stack state.Split it up into
UNWIND_HINT_END_OF_STACKandUNWIND_HINT_UNDEFINED.
Quoted 7 lines
Josh Poimboeuf (6):
objtool: Addobjtool_types.h
objtool: Use relative pointers for annotations
objtool: ChangeUNWIND_HINT()argument order x86,objtool: Introduce ORC_TYPE_*
x86,objtool: Separate unret validation from unwind hints x86,objtool: SplitUNWIND_HINT_EMPTYin two
Quite a bit of churn, but the end result does seem cleaner.