2022-04-20 15:27:21

by Josh Poimboeuf

[permalink] [raw]
Subject: [PATCH v2 00/25] objtool: Interface overhaul

v2:
- extricate sls
- fix ibt regressions in v1
- fix issues found by improved ibt logic
- split '--hacks' into two
- add objdump-func script
- remove "()" in function address strings
- add '--sec-address' option
- add '--link'


Objtool's interface has some issues:

- Several features are done unconditionally, without any way to turn
them off. Some of them might be surprising. This makes objtool
tricky to use, and prevents porting individual features to other
arches.

- The config dependencies are too coarse-grained. Objtool enablement is
tied to CONFIG_STACK_VALIDATION, but it has several other features
independent of that.

- The objtool subcmds ("check" and "orc") are clumsy: "check" is really
a subset of "orc", so it has all the same options. The subcmd model
has never really worked for objtool, as it only has a single purpose:
"do some combination of things on an object file".

- The '--lto' and '--vmlinux' options are nonsensical and have
surprising behavior.


Overhaul the interface:

- get rid of subcmds

- make all features individually selectable

- remove and/or clarify confusing/obsolete options

- update the documentation

- fix some bugs found along the way


TODO: rename files...


$ tools/objtool/objtool --help

Usage: objtool <actions> [<options>] file.o

Actions:
-h, --hacks[=<jump_label,noinstr>]
patch toolchain bugs/limitations
-i, --ibt validate and annotate IBT
-l, --sls validate straight-line-speculation mitigations
-m, --mcount annotate mcount/fentry calls for ftrace
-n, --noinstr validate noinstr rules
-o, --orc generate ORC metadata
-r, --retpoline validate and annotate retpoline usage
-s, --stackval validate frame pointer rules
-t, --static-call annotate static calls
-u, --uaccess validate uaccess rules for SMAP
--dump[=<orc>] dump metadata

Options:
--backtrace unwind on error
--backup create .orig files before modification
--dry-run don't write modifications
--link object is a linked object
--module object is part of a kernel module
--no-unreachable skip 'unreachable instruction' warnings
--sec-address print section addresses in warnings
--stats print statistics



Josh Poimboeuf (25):
objtool: Enable unreachable warnings for CLANG LTO
libsubcmd: Fix OPTION_GROUP sorting
x86/static_call: Add ANNOTATE_NOENDBR to static call trampoline
x86/retpoline: Add ANNOTATE_ENDBR for retpolines
x86/uaccess: Add ENDBR to __put_user_nocheck*()
x86/xen: Add ANNOTATE_ENDBR to startup_xen()
objtool: Reorganize cmdline options
objtool: Ditch subcommands
objtool: Don't print parentheses in function addresses
objtool: Print data address for "!ENDBR" data warnings
objtool: Use offstr() to print address of missing ENDBR
objtool: Add option to print section addresses
scripts: Create objdump-func helper script
objtool: Make stack validation optional
objtool: Rework ibt and extricate from stack validation
objtool: Extricate sls from stack validation
objtool: Add CONFIG_OBJTOOL
objtool: Make stack validation frame-pointer-specific
objtool: Make static call annotation optional
objtool: Make jump label hack optional
objtool: Make noinstr hacks optional
objtool: Rename "VMLINUX_VALIDATION" -> "NOINSTR_VALIDATION"
objtool: Add HAVE_NOINSTR_VALIDATION
objtool: Remove --lto and --vmlinux in favor of --link
objtool: Update documentation

Makefile | 2 +-
arch/Kconfig | 18 +-
arch/x86/Kconfig | 21 +-
arch/x86/Kconfig.debug | 2 +-
arch/x86/include/asm/jump_label.h | 6 +-
arch/x86/include/asm/static_call.h | 1 +
arch/x86/kernel/alternative.c | 6 +-
arch/x86/lib/putuser.S | 4 +
arch/x86/lib/retpoline.S | 2 +-
arch/x86/xen/xen-head.S | 1 +
include/linux/compiler.h | 6 +-
include/linux/instrumentation.h | 6 +-
include/linux/objtool.h | 6 +-
kernel/trace/Kconfig | 1 +
lib/Kconfig.debug | 22 +-
lib/Kconfig.kcsan | 4 +-
lib/Kconfig.ubsan | 2 +-
scripts/Makefile.build | 23 +-
scripts/link-vmlinux.sh | 66 ++-
scripts/objdump-func | 18 +
scripts/package/builddeb | 2 +-
tools/include/linux/objtool.h | 6 +-
tools/lib/subcmd/parse-options.c | 17 +-
tools/objtool/Build | 12 +-
.../{stack-validation.txt => objtool.txt} | 122 ++++-
tools/objtool/Makefile | 8 +-
tools/objtool/arch/x86/decode.c | 2 +-
tools/objtool/arch/x86/special.c | 2 +-
tools/objtool/builtin-check.c | 156 ++++--
tools/objtool/builtin-orc.c | 73 ---
tools/objtool/check.c | 456 ++++++++++--------
tools/objtool/elf.c | 11 +-
tools/objtool/include/objtool/builtin.h | 34 +-
tools/objtool/include/objtool/elf.h | 12 +-
tools/objtool/include/objtool/warn.h | 35 +-
tools/objtool/objtool.c | 103 +---
tools/objtool/weak.c | 9 +-
37 files changed, 719 insertions(+), 558 deletions(-)
create mode 100755 scripts/objdump-func
rename tools/objtool/Documentation/{stack-validation.txt => objtool.txt} (80%)
delete mode 100644 tools/objtool/builtin-orc.c

--
2.34.1


2022-04-20 16:28:28

by Josh Poimboeuf

[permalink] [raw]
Subject: [PATCH v2 04/25] x86/retpoline: Add ANNOTATE_ENDBR for retpolines

The retpolines are exported, so they're referenced by ksymtab sections.
But they're never indirect-branched to, so add ANNOTATE_ENDBR.

Signed-off-by: Josh Poimboeuf <[email protected]>
---
arch/x86/lib/retpoline.S | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S
index 5f87bab4fb8d..b2b2366885a2 100644
--- a/arch/x86/lib/retpoline.S
+++ b/arch/x86/lib/retpoline.S
@@ -31,6 +31,7 @@
.align RETPOLINE_THUNK_SIZE
SYM_INNER_LABEL(__x86_indirect_thunk_\reg, SYM_L_GLOBAL)
UNWIND_HINT_EMPTY
+ ANNOTATE_NOENDBR

ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; jmp *%\reg), \
__stringify(RETPOLINE \reg), X86_FEATURE_RETPOLINE, \
@@ -55,7 +56,6 @@ SYM_INNER_LABEL(__x86_indirect_thunk_\reg, SYM_L_GLOBAL)

.align RETPOLINE_THUNK_SIZE
SYM_CODE_START(__x86_indirect_thunk_array)
- ANNOTATE_NOENDBR // apply_retpolines

#define GEN(reg) THUNK reg
#include <asm/GEN-for-each-reg.h>
--
2.34.1

Subject: [tip: x86/urgent] x86/retpoline: Add ANNOTATE_NOENDBR for retpolines

The following commit has been merged into the x86/urgent branch of tip:

Commit-ID: 1c0513dec41e4d40eb21402dff397ad84ca13a44
Gitweb: https://git.kernel.org/tip/1c0513dec41e4d40eb21402dff397ad84ca13a44
Author: Josh Poimboeuf <[email protected]>
AuthorDate: Mon, 18 Apr 2022 09:50:23 -07:00
Committer: Peter Zijlstra <[email protected]>
CommitterDate: Tue, 19 Apr 2022 21:58:49 +02:00

x86/retpoline: Add ANNOTATE_NOENDBR for retpolines

The retpolines are exported, so they're referenced by ksymtab sections.
But they're never indirect-branched to, so add ANNOTATE_NOENDBR.

Fixes: ed53a0d97192 ("x86/alternative: Use .ibt_endbr_seal to seal indirect calls")
Signed-off-by: Josh Poimboeuf <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
Link: https://lkml.kernel.org/r/b6ec963dfd9301b6b1d74ef7758fcb0b540d6c6c.1650300597.git.jpoimboe@redhat.com
---
arch/x86/lib/retpoline.S | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S
index 5f87bab..b2b2366 100644
--- a/arch/x86/lib/retpoline.S
+++ b/arch/x86/lib/retpoline.S
@@ -31,6 +31,7 @@
.align RETPOLINE_THUNK_SIZE
SYM_INNER_LABEL(__x86_indirect_thunk_\reg, SYM_L_GLOBAL)
UNWIND_HINT_EMPTY
+ ANNOTATE_NOENDBR

ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; jmp *%\reg), \
__stringify(RETPOLINE \reg), X86_FEATURE_RETPOLINE, \
@@ -55,7 +56,6 @@ SYM_INNER_LABEL(__x86_indirect_thunk_\reg, SYM_L_GLOBAL)

.align RETPOLINE_THUNK_SIZE
SYM_CODE_START(__x86_indirect_thunk_array)
- ANNOTATE_NOENDBR // apply_retpolines

#define GEN(reg) THUNK reg
#include <asm/GEN-for-each-reg.h>

2022-04-20 23:01:08

by Josh Poimboeuf

[permalink] [raw]
Subject: [PATCH v2 22/25] objtool: Rename "VMLINUX_VALIDATION" -> "NOINSTR_VALIDATION"

CONFIG_VMLINUX_VALIDATION is just the validation of the "noinstr" rules.
That name is a misnomer, because now objtool actually does vmlinux
validation for other reasons.

Rename CONFIG_VMLINUX_VALIDATION to CONFIG_NOINSTR_VALIDATION.

Signed-off-by: Josh Poimboeuf <[email protected]>
---
include/linux/instrumentation.h | 6 +++---
lib/Kconfig.debug | 2 +-
scripts/link-vmlinux.sh | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/include/linux/instrumentation.h b/include/linux/instrumentation.h
index 9111a3704072..bc7babe91b2e 100644
--- a/include/linux/instrumentation.h
+++ b/include/linux/instrumentation.h
@@ -2,7 +2,7 @@
#ifndef __LINUX_INSTRUMENTATION_H
#define __LINUX_INSTRUMENTATION_H

-#ifdef CONFIG_VMLINUX_VALIDATION
+#ifdef CONFIG_NOINSTR_VALIDATION

#include <linux/stringify.h>

@@ -53,9 +53,9 @@
".popsection\n\t" : : "i" (c)); \
})
#define instrumentation_end() __instrumentation_end(__COUNTER__)
-#else /* !CONFIG_VMLINUX_VALIDATION */
+#else /* !CONFIG_NOINSTR_VALIDATION */
# define instrumentation_begin() do { } while(0)
# define instrumentation_end() do { } while(0)
-#endif /* CONFIG_VMLINUX_VALIDATION */
+#endif /* CONFIG_NOINSTR_VALIDATION */

#endif /* __LINUX_INSTRUMENTATION_H */
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 7d2bbc3e558e..73359d6cd9a2 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -500,7 +500,7 @@ config STACK_VALIDATION
For more information, see
tools/objtool/Documentation/stack-validation.txt.

-config VMLINUX_VALIDATION
+config NOINSTR_VALIDATION
bool
depends on HAVE_OBJTOOL && DEBUG_ENTRY
select OBJTOOL
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 90c9c4c05d95..fce4f41816cd 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -160,7 +160,7 @@ objtool_link()
objtoolopt="${objtoolopt} --lto"
fi

- if is_enabled CONFIG_VMLINUX_VALIDATION; then
+ if is_enabled CONFIG_NOINSTR_VALIDATION; then
objtoolopt="${objtoolopt} --noinstr"
fi

--
2.34.1

2022-04-21 05:15:33

by Josh Poimboeuf

[permalink] [raw]
Subject: [PATCH v2 24/25] objtool: Remove --lto and --vmlinux in favor of --link

The '--lto' option is a confusing way of telling objtool to do stack
validation despite it being a linked object. It's no longer needed now
that an explicit '--stackval' option exists. The '--vmlinux' option is
also redundant.

Remove both options in favor of a straightforward '--link' option which
identifies a linked object.

Also, implicitly set '--link' with a warning if the user forgets to do
so and we can tell that it's a linked object. This makes it easier for
manual vmlinux runs.

Signed-off-by: Josh Poimboeuf <[email protected]>
---
scripts/Makefile.build | 4 ++-
scripts/link-vmlinux.sh | 8 ++---
tools/objtool/builtin-check.c | 39 +++++++++++++++++++++---
tools/objtool/check.c | 40 +++++++++----------------
tools/objtool/elf.c | 3 ++
tools/objtool/include/objtool/builtin.h | 3 +-
tools/objtool/include/objtool/elf.h | 12 +++++++-
7 files changed, 70 insertions(+), 39 deletions(-)

diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 6c206a1bab97..ac8167227bc0 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -229,7 +229,7 @@ objtool := $(objtree)/tools/objtool/objtool
objtool_args = \
$(if $(CONFIG_HAVE_JUMP_LABEL_HACK), --hacks=jump_label) \
$(if $(CONFIG_HAVE_NOINSTR_HACK), --hacks=noinstr) \
- $(if $(CONFIG_X86_KERNEL_IBT), --lto --ibt) \
+ $(if $(CONFIG_X86_KERNEL_IBT), --ibt) \
$(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \
$(if $(CONFIG_UNWINDER_ORC), --orc) \
$(if $(CONFIG_RETPOLINE), --retpoline) \
@@ -237,6 +237,7 @@ objtool_args = \
$(if $(CONFIG_STACK_VALIDATION), --stackval) \
$(if $(CONFIG_HAVE_STATIC_CALL_INLINE), --static-call) \
$(if $(CONFIG_X86_SMAP), --uaccess) \
+ $(if $(linked-object), --link) \
$(if $(part-of-module), --module) \
$(if $(CONFIG_GCOV_KERNEL), --no-unreachable)

@@ -306,6 +307,7 @@ quiet_cmd_cc_prelink_modules = LD [M] $@
# modules into native code
$(obj)/%.prelink.o: objtool-enabled = y
$(obj)/%.prelink.o: part-of-module := y
+$(obj)/%.prelink.o: linked-object := y

$(obj)/%.prelink.o: $(obj)/%.o FORCE
$(call if_changed,cc_prelink_modules)
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index fce4f41816cd..eb9324f07f3d 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -114,8 +114,8 @@ objtool_link()

if is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT; then

- # Don't perform vmlinux validation unless explicitly requested,
- # but run objtool on vmlinux.o now that we have an object file.
+ # For LTO and IBT, objtool doesn't run on individual
+ # translation units. Run everything on vmlinux instead.

if is_enabled CONFIG_HAVE_JUMP_LABEL_HACK; then
objtoolopt="${objtoolopt} --hacks=jump_label"
@@ -156,8 +156,6 @@ objtool_link()
if is_enabled CONFIG_X86_SMAP; then
objtoolopt="${objtoolopt} --uaccess"
fi
-
- objtoolopt="${objtoolopt} --lto"
fi

if is_enabled CONFIG_NOINSTR_VALIDATION; then
@@ -170,7 +168,7 @@ objtool_link()
objtoolopt="${objtoolopt} --no-unreachable"
fi

- objtoolopt="${objtoolopt} --vmlinux"
+ objtoolopt="${objtoolopt} --link"

info OBJTOOL ${1}
tools/objtool/objtool ${objtoolopt} ${1}
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index 1803a63147e4..f4c3a5091737 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -9,6 +9,11 @@
#include <objtool/builtin.h>
#include <objtool/objtool.h>

+#define ERROR(format, ...) \
+ fprintf(stderr, \
+ "error: objtool: " format "\n", \
+ ##__VA_ARGS__)
+
struct opts opts;

static const char * const check_usage[] = {
@@ -73,12 +78,11 @@ const struct option check_options[] = {
OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"),
OPT_BOOLEAN(0, "backup", &opts.backup, "create .orig files before modification"),
OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"),
- OPT_BOOLEAN(0, "lto", &opts.lto, "whole-archive like runs"),
+ OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"),
OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"),
OPT_BOOLEAN(0, "no-unreachable", &opts.no_unreachable, "skip 'unreachable instruction' warnings"),
OPT_BOOLEAN(0, "sec-address", &opts.sec_address, "print section addresses in warnings"),
OPT_BOOLEAN(0, "stats", &opts.stats, "print statistics"),
- OPT_BOOLEAN(0, "vmlinux", &opts.vmlinux, "vmlinux.o validation"),

OPT_END(),
};
@@ -124,7 +128,7 @@ static bool opts_valid(void)
opts.static_call ||
opts.uaccess) {
if (opts.dump_orc) {
- fprintf(stderr, "--dump can't be combined with other options\n");
+ ERROR("--dump can't be combined with other options");
return false;
}

@@ -134,10 +138,34 @@ static bool opts_valid(void)
if (opts.dump_orc)
return true;

- fprintf(stderr, "At least one command required\n");
+ ERROR("At least one command required");
return false;
}

+static bool link_opts_valid(struct objtool_file *file)
+{
+ if (opts.link)
+ return true;
+
+ if (has_multiple_files(file->elf)) {
+ ERROR("Linked object detected, forcing --link");
+ opts.link = true;
+ return true;
+ }
+
+ if (opts.noinstr) {
+ ERROR("--noinstr requires --link");
+ return false;
+ }
+
+ if (opts.ibt) {
+ ERROR("--ibt requires --link");
+ return false;
+ }
+
+ return true;
+}
+
int objtool_run(int argc, const char **argv)
{
const char *objname;
@@ -157,6 +185,9 @@ int objtool_run(int argc, const char **argv)
if (!file)
return 1;

+ if (!link_opts_valid(file))
+ return 1;
+
ret = check(file);
if (ret)
return ret;
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 6a7b5fa3fe1b..60b6a2a712b5 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -264,7 +264,8 @@ static void init_cfi_state(struct cfi_state *cfi)
cfi->drap_offset = -1;
}

-static void init_insn_state(struct insn_state *state, struct section *sec)
+static void init_insn_state(struct objtool_file *file, struct insn_state *state,
+ struct section *sec)
{
memset(state, 0, sizeof(*state));
init_cfi_state(&state->cfi);
@@ -274,7 +275,7 @@ static void init_insn_state(struct insn_state *state, struct section *sec)
* not correctly determine insn->call_dest->sec (external symbols do
* not have a section).
*/
- if (opts.vmlinux && opts.noinstr && sec)
+ if (opts.link && opts.noinstr && sec)
state->noinstr = sec->noinstr;
}

@@ -3406,7 +3407,7 @@ static int validate_unwind_hints(struct objtool_file *file, struct section *sec)
if (!file->hints)
return 0;

- init_insn_state(&state, sec);
+ init_insn_state(file, &state, sec);

if (sec) {
insn = find_insn(file, sec, 0);
@@ -3492,14 +3493,14 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio
return true;

/*
- * Whole archive runs might encounder dead code from weak symbols.
+ * Whole archive runs might encounter dead code from weak symbols.
* This is where the linker will have dropped the weak symbol in
* favour of a regular symbol, but leaves the code in place.
*
* In this case we'll find a piece of code (whole function) that is not
* covered by a !section symbol. Ignore them.
*/
- if (!insn->func && opts.lto) {
+ if (opts.link && !insn->func) {
int size = find_symbol_hole_containing(insn->sec, insn->offset);
unsigned long end = insn->offset + size;

@@ -3621,7 +3622,7 @@ static int validate_section(struct objtool_file *file, struct section *sec)
if (func->type != STT_FUNC)
continue;

- init_insn_state(&state, sec);
+ init_insn_state(file, &state, sec);
set_func_state(&state.cfi);

warnings += validate_symbol(file, sec, func, &state);
@@ -3630,7 +3631,7 @@ static int validate_section(struct objtool_file *file, struct section *sec)
return warnings;
}

-static int validate_vmlinux_functions(struct objtool_file *file)
+static int validate_noinstr_sections(struct objtool_file *file)
{
struct section *sec;
int warnings = 0;
@@ -3891,16 +3892,6 @@ int check(struct objtool_file *file)
{
int ret, warnings = 0;

- if (opts.lto && !(opts.vmlinux || opts.module)) {
- fprintf(stderr, "--lto requires: --vmlinux or --module\n");
- return 1;
- }
-
- if (opts.ibt && !opts.lto) {
- fprintf(stderr, "--ibt requires: --lto\n");
- return 1;
- }
-
arch_initial_func_cfi_state(&initial_func_cfi);
init_cfi_state(&init_cfi);
init_cfi_state(&func_cfi);
@@ -3921,15 +3912,6 @@ int check(struct objtool_file *file)
if (list_empty(&file->insn_list))
goto out;

- if (opts.vmlinux && !opts.lto) {
- ret = validate_vmlinux_functions(file);
- if (ret < 0)
- goto out;
-
- warnings += ret;
- goto out;
- }
-
if (opts.retpoline) {
ret = validate_retpoline(file);
if (ret < 0)
@@ -3954,6 +3936,12 @@ int check(struct objtool_file *file)
goto out;
warnings += ret;
}
+
+ } else if (opts.noinstr) {
+ ret = validate_noinstr_sections(file);
+ if (ret < 0)
+ goto out;
+ warnings += ret;
}

if (opts.ibt) {
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index f7b2ad27bb1c..41fea838aeba 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -377,6 +377,9 @@ static void elf_add_symbol(struct elf *elf, struct symbol *sym)
sym->type = GELF_ST_TYPE(sym->sym.st_info);
sym->bind = GELF_ST_BIND(sym->sym.st_info);

+ if (sym->type == STT_FILE)
+ elf->num_files++;
+
sym->offset = sym->sym.st_value;
sym->len = sym->sym.st_size;

diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h
index f3a1a754b5c4..280ea18b7f2b 100644
--- a/tools/objtool/include/objtool/builtin.h
+++ b/tools/objtool/include/objtool/builtin.h
@@ -28,12 +28,11 @@ struct opts {
bool backtrace;
bool backup;
bool dryrun;
- bool lto;
+ bool link;
bool module;
bool no_unreachable;
bool sec_address;
bool stats;
- bool vmlinux;
};

extern struct opts opts;
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index 22ba7e2b816e..9bb1e20c4462 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -86,7 +86,7 @@ struct elf {
int fd;
bool changed;
char *name;
- unsigned int text_size;
+ unsigned int text_size, num_files;
struct list_head sections;

int symbol_bits;
@@ -131,6 +131,16 @@ static inline u32 reloc_hash(struct reloc *reloc)
return sec_offset_hash(reloc->sec, reloc->offset);
}

+/*
+ * Try to see if it's a whole archive (vmlinux.o or module).
+ *
+ * Note this will miss the case where a module only has one source file.
+ */
+static inline bool has_multiple_files(struct elf *elf)
+{
+ return elf->num_files > 1;
+}
+
struct elf *elf_open_read(const char *name, int flags);
struct section *elf_create_section(struct elf *elf, const char *name, unsigned int sh_flags, size_t entsize, int nr);

--
2.34.1

2022-04-21 06:18:37

by Josh Poimboeuf

[permalink] [raw]
Subject: [PATCH v2 06/25] x86/xen: Add ANNOTATE_ENDBR to startup_xen()

The startup_xen() kernel entry point is referenced by the ".note.Xen"
section, but is presumably not indirect-branched to. Add ANNOTATE_ENDBR
to silence future objtool warnings.

Cc: Boris Ostrovsky <[email protected]>
Cc: Juergen Gross <[email protected]>
Cc: Stefano Stabellini <[email protected]>
Cc: [email protected]
Signed-off-by: Josh Poimboeuf <[email protected]>
---
arch/x86/xen/xen-head.S | 1 +
1 file changed, 1 insertion(+)

diff --git a/arch/x86/xen/xen-head.S b/arch/x86/xen/xen-head.S
index ac17196e2518..3a2cd93bf059 100644
--- a/arch/x86/xen/xen-head.S
+++ b/arch/x86/xen/xen-head.S
@@ -45,6 +45,7 @@ SYM_CODE_END(hypercall_page)
__INIT
SYM_CODE_START(startup_xen)
UNWIND_HINT_EMPTY
+ ANNOTATE_NOENDBR
cld

/* Clear .bss */
--
2.34.1

2022-04-21 07:20:35

by Josh Poimboeuf

[permalink] [raw]
Subject: [PATCH v2 08/25] objtool: Ditch subcommands

Objtool has a fairly singular focus. It runs on object files and does
validations and transformations which can be combined in various ways.
The subcommand model has never been a good fit, making it awkward to
combine and remove options.

Remove the "check" and "orc" subcommands in favor of a more traditional
cmdline option model. This makes it much more flexible to use, and
easier to port individual features to other arches.

Signed-off-by: Josh Poimboeuf <[email protected]>
---
scripts/Makefile.build | 2 +-
scripts/link-vmlinux.sh | 13 ++--
tools/objtool/Build | 12 ++-
tools/objtool/Makefile | 8 +-
tools/objtool/builtin-check.c | 56 +++++++++++---
tools/objtool/builtin-orc.c | 73 -------------------
tools/objtool/check.c | 8 ++
tools/objtool/include/objtool/builtin.h | 5 +-
tools/objtool/objtool.c | 97 +------------------------
tools/objtool/weak.c | 9 +--
10 files changed, 72 insertions(+), 211 deletions(-)
delete mode 100644 tools/objtool/builtin-orc.c

diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index dd9d582808d6..116c7272b41c 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -227,9 +227,9 @@ ifdef CONFIG_STACK_VALIDATION
objtool := $(objtree)/tools/objtool/objtool

objtool_args = \
- $(if $(CONFIG_UNWINDER_ORC),orc generate,check) \
$(if $(CONFIG_X86_KERNEL_IBT), --lto --ibt) \
$(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \
+ $(if $(CONFIG_UNWINDER_ORC), --orc) \
$(if $(CONFIG_RETPOLINE), --retpoline) \
$(if $(CONFIG_SLS), --sls) \
$(if $(CONFIG_X86_SMAP), --uaccess) \
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index c6e9fef61b11..f6db79b11573 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -113,9 +113,6 @@ objtool_link()

# Don't perform vmlinux validation unless explicitly requested,
# but run objtool on vmlinux.o now that we have an object file.
- if is_enabled CONFIG_UNWINDER_ORC; then
- objtoolcmd="orc generate"
- fi

if is_enabled CONFIG_X86_KERNEL_IBT; then
objtoolopt="${objtoolopt} --ibt"
@@ -125,6 +122,10 @@ objtool_link()
objtoolopt="${objtoolopt} --mcount"
fi

+ if is_enabled CONFIG_UNWINDER_ORC; then
+ objtoolopt="${objtoolopt} --orc"
+ fi
+
objtoolopt="${objtoolopt} --lto"
fi

@@ -134,10 +135,6 @@ objtool_link()

if [ -n "${objtoolopt}" ]; then

- if [ -z "${objtoolcmd}" ]; then
- objtoolcmd="check"
- fi
-
if is_enabled CONFIG_RETPOLINE; then
objtoolopt="${objtoolopt} --retpoline"
fi
@@ -161,7 +158,7 @@ objtool_link()
objtoolopt="${objtoolopt} --vmlinux"

info OBJTOOL ${1}
- tools/objtool/objtool ${objtoolcmd} ${objtoolopt} ${1}
+ tools/objtool/objtool ${objtoolopt} ${1}
fi
}

diff --git a/tools/objtool/Build b/tools/objtool/Build
index b7222d5cc7bc..33f2ee5a46d3 100644
--- a/tools/objtool/Build
+++ b/tools/objtool/Build
@@ -2,17 +2,15 @@ objtool-y += arch/$(SRCARCH)/

objtool-y += weak.o

-objtool-$(SUBCMD_CHECK) += check.o
-objtool-$(SUBCMD_CHECK) += special.o
-objtool-$(SUBCMD_ORC) += check.o
-objtool-$(SUBCMD_ORC) += orc_gen.o
-objtool-$(SUBCMD_ORC) += orc_dump.o
-
+objtool-y += check.o
+objtool-y += special.o
objtool-y += builtin-check.o
-objtool-y += builtin-orc.o
objtool-y += elf.o
objtool-y += objtool.o

+objtool-$(BUILD_ORC) += orc_gen.o
+objtool-$(BUILD_ORC) += orc_dump.o
+
objtool-y += libstring.o
objtool-y += libctype.o
objtool-y += str_error_r.o
diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile
index 0dbd397f319d..061cf1cd42c4 100644
--- a/tools/objtool/Makefile
+++ b/tools/objtool/Makefile
@@ -39,15 +39,13 @@ CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED)

AWK = awk

-SUBCMD_CHECK := n
-SUBCMD_ORC := n
+BUILD_ORC := n

ifeq ($(SRCARCH),x86)
- SUBCMD_CHECK := y
- SUBCMD_ORC := y
+ BUILD_ORC := y
endif

-export SUBCMD_CHECK SUBCMD_ORC
+export BUILD_ORC
export srctree OUTPUT CFLAGS SRCARCH AWK
include $(srctree)/tools/build/Makefile.include

diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index bc447b3cd9f2..8c3eed5b67e4 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -3,16 +3,6 @@
* Copyright (C) 2015-2017 Josh Poimboeuf <[email protected]>
*/

-/*
- * objtool check:
- *
- * This command analyzes every .o file and ensures the validity of its stack
- * trace metadata. It enforces a set of rules on asm code and C inline
- * assembly code so that stack traces can be reliable.
- *
- * For more information, see tools/objtool/Documentation/stack-validation.txt.
- */
-
#include <subcmd/parse-options.h>
#include <string.h>
#include <stdlib.h>
@@ -22,7 +12,7 @@
struct opts opts;

static const char * const check_usage[] = {
- "objtool check <actions> [<options>] file.o",
+ "objtool <actions> [<options>] file.o",
NULL,
};

@@ -31,14 +21,26 @@ static const char * const env_usage[] = {
NULL,
};

+static int parse_dump(const struct option *opt, const char *str, int unset)
+{
+ if (!str || !strcmp(str, "orc")) {
+ opts.dump_orc = true;
+ return 0;
+ }
+
+ return -1;
+}
+
const struct option check_options[] = {
OPT_GROUP("Actions:"),
OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"),
OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls for ftrace"),
OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"),
+ OPT_BOOLEAN('o', "orc", &opts.orc, "generate ORC metadata"),
OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate retpoline usage"),
OPT_BOOLEAN('l', "sls", &opts.sls, "validate straight-line-speculation mitigations"),
OPT_BOOLEAN('u', "uaccess", &opts.uaccess, "validate uaccess rules for SMAP"),
+ OPT_CALLBACK_OPTARG(0, "dump", NULL, NULL, "orc", "dump metadata", parse_dump),

OPT_GROUP("Options:"),
OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"),
@@ -81,7 +83,31 @@ int cmd_parse_options(int argc, const char **argv, const char * const usage[])
return argc;
}

-int cmd_check(int argc, const char **argv)
+static bool opts_valid(void)
+{
+ if (opts.ibt ||
+ opts.mcount ||
+ opts.noinstr ||
+ opts.orc ||
+ opts.retpoline ||
+ opts.sls ||
+ opts.uaccess) {
+ if (opts.dump_orc) {
+ fprintf(stderr, "--dump can't be combined with other options\n");
+ return false;
+ }
+
+ return true;
+ }
+
+ if (opts.dump_orc)
+ return true;
+
+ fprintf(stderr, "At least one command required\n");
+ return false;
+}
+
+int objtool_run(int argc, const char **argv)
{
const char *objname;
struct objtool_file *file;
@@ -90,6 +116,12 @@ int cmd_check(int argc, const char **argv)
argc = cmd_parse_options(argc, argv, check_usage);
objname = argv[0];

+ if (!opts_valid())
+ return 1;
+
+ if (opts.dump_orc)
+ return orc_dump(objname);
+
file = objtool_open_read(objname);
if (!file)
return 1;
diff --git a/tools/objtool/builtin-orc.c b/tools/objtool/builtin-orc.c
deleted file mode 100644
index 17f8b9307738..000000000000
--- a/tools/objtool/builtin-orc.c
+++ /dev/null
@@ -1,73 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2017 Josh Poimboeuf <[email protected]>
- */
-
-/*
- * objtool orc:
- *
- * This command analyzes a .o file and adds .orc_unwind and .orc_unwind_ip
- * sections to it, which is used by the in-kernel ORC unwinder.
- *
- * This command is a superset of "objtool check".
- */
-
-#include <string.h>
-#include <objtool/builtin.h>
-#include <objtool/objtool.h>
-
-static const char *orc_usage[] = {
- "objtool orc generate [<options>] file.o",
- "objtool orc dump file.o",
- NULL,
-};
-
-int cmd_orc(int argc, const char **argv)
-{
- const char *objname;
-
- argc--; argv++;
- if (argc <= 0)
- usage_with_options(orc_usage, check_options);
-
- if (!strncmp(argv[0], "gen", 3)) {
- struct objtool_file *file;
- int ret;
-
- argc = cmd_parse_options(argc, argv, orc_usage);
- objname = argv[0];
-
- file = objtool_open_read(objname);
- if (!file)
- return 1;
-
- ret = check(file);
- if (ret)
- return ret;
-
- if (list_empty(&file->insn_list))
- return 0;
-
- ret = orc_create(file);
- if (ret)
- return ret;
-
- if (!file->elf->changed)
- return 0;
-
- return elf_write(file->elf);
- }
-
- if (!strcmp(argv[0], "dump")) {
- if (argc != 2)
- usage_with_options(orc_usage, check_options);
-
- objname = argv[1];
-
- return orc_dump(objname);
- }
-
- usage_with_options(orc_usage, check_options);
-
- return 0;
-}
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 980f7bb0e954..acf26d273e2f 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -3954,6 +3954,14 @@ int check(struct objtool_file *file)
warnings += ret;
}

+ if (opts.orc && !list_empty(&file->insn_list)) {
+ ret = orc_create(file);
+ if (ret < 0)
+ goto out;
+ warnings += ret;
+ }
+
+
if (opts.stats) {
printf("nr_insns_visited: %ld\n", nr_insns_visited);
printf("nr_cfi: %ld\n", nr_cfi);
diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h
index 87c1a7351e3c..44548e24473c 100644
--- a/tools/objtool/include/objtool/builtin.h
+++ b/tools/objtool/include/objtool/builtin.h
@@ -11,9 +11,11 @@ extern const struct option check_options[];

struct opts {
/* actions: */
+ bool dump_orc;
bool ibt;
bool mcount;
bool noinstr;
+ bool orc;
bool retpoline;
bool sls;
bool uaccess;
@@ -34,7 +36,6 @@ extern struct opts opts;

extern int cmd_parse_options(int argc, const char **argv, const char * const usage[]);

-extern int cmd_check(int argc, const char **argv);
-extern int cmd_orc(int argc, const char **argv);
+extern int objtool_run(int argc, const char **argv);

#endif /* _BUILTIN_H */
diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c
index a0f3d3c9558d..512669ce064c 100644
--- a/tools/objtool/objtool.c
+++ b/tools/objtool/objtool.c
@@ -3,16 +3,6 @@
* Copyright (C) 2015 Josh Poimboeuf <[email protected]>
*/

-/*
- * objtool:
- *
- * The 'check' subcmd analyzes every .o file and ensures the validity of its
- * stack trace metadata. It enforces a set of rules on asm code and C inline
- * assembly code so that stack traces can be reliable.
- *
- * For more information, see tools/objtool/Documentation/stack-validation.txt.
- */
-
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
@@ -26,20 +16,6 @@
#include <objtool/objtool.h>
#include <objtool/warn.h>

-struct cmd_struct {
- const char *name;
- int (*fn)(int, const char **);
- const char *help;
-};
-
-static const char objtool_usage_string[] =
- "objtool COMMAND [ARGS]";
-
-static struct cmd_struct objtool_cmds[] = {
- {"check", cmd_check, "Perform stack metadata validation on an object file" },
- {"orc", cmd_orc, "Generate in-place ORC unwind tables for an object file" },
-};
-
bool help;

const char *objname;
@@ -161,70 +137,6 @@ void objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func)
f->pv_ops[idx].clean = false;
}

-static void cmd_usage(void)
-{
- unsigned int i, longest = 0;
-
- printf("\n usage: %s\n\n", objtool_usage_string);
-
- for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) {
- if (longest < strlen(objtool_cmds[i].name))
- longest = strlen(objtool_cmds[i].name);
- }
-
- puts(" Commands:");
- for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) {
- printf(" %-*s ", longest, objtool_cmds[i].name);
- puts(objtool_cmds[i].help);
- }
-
- printf("\n");
-
- if (!help)
- exit(129);
- exit(0);
-}
-
-static void handle_options(int *argc, const char ***argv)
-{
- while (*argc > 0) {
- const char *cmd = (*argv)[0];
-
- if (cmd[0] != '-')
- break;
-
- if (!strcmp(cmd, "--help") || !strcmp(cmd, "-h")) {
- help = true;
- break;
- } else {
- fprintf(stderr, "Unknown option: %s\n", cmd);
- cmd_usage();
- }
-
- (*argv)++;
- (*argc)--;
- }
-}
-
-static void handle_internal_command(int argc, const char **argv)
-{
- const char *cmd = argv[0];
- unsigned int i, ret;
-
- for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) {
- struct cmd_struct *p = objtool_cmds+i;
-
- if (strcmp(p->name, cmd))
- continue;
-
- ret = p->fn(argc, argv);
-
- exit(ret);
- }
-
- cmd_usage();
-}
-
int main(int argc, const char **argv)
{
static const char *UNUSED = "OBJTOOL_NOT_IMPLEMENTED";
@@ -233,14 +145,7 @@ int main(int argc, const char **argv)
exec_cmd_init("objtool", UNUSED, UNUSED, UNUSED);
pager_init(UNUSED);

- argv++;
- argc--;
- handle_options(&argc, &argv);
-
- if (!argc || help)
- cmd_usage();
-
- handle_internal_command(argc, argv);
+ objtool_run(argc, argv);

return 0;
}
diff --git a/tools/objtool/weak.c b/tools/objtool/weak.c
index 8314e824db4a..d83f607733b0 100644
--- a/tools/objtool/weak.c
+++ b/tools/objtool/weak.c
@@ -15,17 +15,12 @@
return ENOSYS; \
})

-int __weak check(struct objtool_file *file)
-{
- UNSUPPORTED("check subcommand");
-}
-
int __weak orc_dump(const char *_objname)
{
- UNSUPPORTED("orc");
+ UNSUPPORTED("ORC");
}

int __weak orc_create(struct objtool_file *file)
{
- UNSUPPORTED("orc");
+ UNSUPPORTED("ORC");
}
--
2.34.1

2022-04-21 08:10:01

by Josh Poimboeuf

[permalink] [raw]
Subject: [PATCH v2 17/25] objtool: Add CONFIG_OBJTOOL

Now that stack validation is an optional feature of objtool, add
CONFIG_OBJTOOL and replace most usages of CONFIG_STACK_VALIDATION with
it.

CONFIG_STACK_VALIDATION can now be considered to be frame-pointer
specific. CONFIG_UNWINDER_ORC is already inherently valid for live
patching, so no need to "validate" it.

Signed-off-by: Josh Poimboeuf <[email protected]>
---
Makefile | 2 +-
arch/Kconfig | 8 ++++++--
arch/x86/Kconfig | 18 ++++++++++-------
arch/x86/Kconfig.debug | 2 +-
arch/x86/include/asm/jump_label.h | 6 +++---
arch/x86/kernel/alternative.c | 6 +++---
include/linux/compiler.h | 6 +++---
include/linux/instrumentation.h | 6 +++---
include/linux/objtool.h | 6 +++---
kernel/trace/Kconfig | 1 +
lib/Kconfig.debug | 20 ++++++++++---------
lib/Kconfig.kcsan | 3 ++-
lib/Kconfig.ubsan | 2 +-
scripts/Makefile.build | 4 ++--
scripts/link-vmlinux.sh | 32 +++++++++++++++++--------------
scripts/package/builddeb | 2 +-
tools/include/linux/objtool.h | 6 +++---
17 files changed, 73 insertions(+), 57 deletions(-)

diff --git a/Makefile b/Makefile
index 29e273d3f8cc..707dfbf643a2 100644
--- a/Makefile
+++ b/Makefile
@@ -1302,7 +1302,7 @@ install: sub_make_done :=
# ---------------------------------------------------------------------------
# Tools

-ifdef CONFIG_STACK_VALIDATION
+ifdef CONFIG_OBJTOOL
prepare: tools/objtool
endif

diff --git a/arch/Kconfig b/arch/Kconfig
index 29b0167c088b..04cdef16db24 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -1028,11 +1028,14 @@ config ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
depends on MMU
select ARCH_HAS_ELF_RANDOMIZE

+config HAVE_OBJTOOL
+ bool
+
config HAVE_STACK_VALIDATION
bool
help
- Architecture supports the 'objtool check' host tool command, which
- performs compile-time stack metadata validation.
+ Architecture supports objtool compile-time frame pointer rule
+ validation.

config HAVE_RELIABLE_STACKTRACE
bool
@@ -1302,6 +1305,7 @@ config HAVE_STATIC_CALL
config HAVE_STATIC_CALL_INLINE
bool
depends on HAVE_STATIC_CALL
+ select OBJTOOL

config HAVE_PREEMPT_DYNAMIC
bool
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index b0142e01002e..bce0c23f3550 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -188,7 +188,7 @@ config X86
select HAVE_CONTEXT_TRACKING if X86_64
select HAVE_CONTEXT_TRACKING_OFFSTACK if HAVE_CONTEXT_TRACKING
select HAVE_C_RECORDMCOUNT
- select HAVE_OBJTOOL_MCOUNT if STACK_VALIDATION
+ select HAVE_OBJTOOL_MCOUNT if HAVE_OBJTOOL
select HAVE_BUILDTIME_MCOUNT_SORT
select HAVE_DEBUG_KMEMLEAK
select HAVE_DMA_CONTIGUOUS
@@ -231,6 +231,7 @@ config X86
select HAVE_MOVE_PMD
select HAVE_MOVE_PUD
select HAVE_NMI
+ select HAVE_OBJTOOL if X86_64
select HAVE_OPTPROBES
select HAVE_PCSPKR_PLATFORM
select HAVE_PERF_EVENTS
@@ -239,17 +240,17 @@ config X86
select HAVE_PCI
select HAVE_PERF_REGS
select HAVE_PERF_USER_STACK_DUMP
- select MMU_GATHER_RCU_TABLE_FREE if PARAVIRT
+ select MMU_GATHER_RCU_TABLE_FREE if PARAVIRT
select HAVE_POSIX_CPU_TIMERS_TASK_WORK
select HAVE_REGS_AND_STACK_ACCESS_API
- select HAVE_RELIABLE_STACKTRACE if X86_64 && (UNWINDER_FRAME_POINTER || UNWINDER_ORC) && STACK_VALIDATION
+ select HAVE_RELIABLE_STACKTRACE if UNWINDER_ORC || STACK_VALIDATION
select HAVE_FUNCTION_ARG_ACCESS_API
select HAVE_SETUP_PER_CPU_AREA
select HAVE_SOFTIRQ_ON_OWN_STACK
select HAVE_STACKPROTECTOR if CC_HAS_SANE_STACKPROTECTOR
- select HAVE_STACK_VALIDATION if X86_64
+ select HAVE_STACK_VALIDATION if HAVE_OBJTOOL
select HAVE_STATIC_CALL
- select HAVE_STATIC_CALL_INLINE if HAVE_STACK_VALIDATION
+ select HAVE_STATIC_CALL_INLINE if HAVE_OBJTOOL
select HAVE_PREEMPT_DYNAMIC_CALL
select HAVE_RSEQ
select HAVE_SYSCALL_TRACEPOINTS
@@ -268,7 +269,6 @@ config X86
select RTC_MC146818_LIB
select SPARSE_IRQ
select SRCU
- select STACK_VALIDATION if HAVE_STACK_VALIDATION && (HAVE_STATIC_CALL_INLINE || RETPOLINE)
select SYSCTL_EXCEPTION_TRACE
select THREAD_INFO_IN_TASK
select TRACE_IRQFLAGS_SUPPORT
@@ -459,6 +459,7 @@ config GOLDFISH

config RETPOLINE
bool "Avoid speculative indirect branches in kernel"
+ select OBJTOOL if HAVE_OBJTOOL
default y
help
Compile kernel with the retpoline compiler options to guard against
@@ -472,6 +473,7 @@ config CC_HAS_SLS
config SLS
bool "Mitigate Straight-Line-Speculation"
depends on CC_HAS_SLS && X86_64
+ select OBJTOOL if HAVE_OBJTOOL
default n
help
Compile the kernel with straight-line-speculation options to guard
@@ -1819,6 +1821,7 @@ config ARCH_RANDOM
config X86_SMAP
def_bool y
prompt "Supervisor Mode Access Prevention" if EXPERT
+ select OBJTOOL if HAVE_OBJTOOL
help
Supervisor Mode Access Prevention (SMAP) is a security
feature in newer Intel processors. There is a small
@@ -1855,9 +1858,10 @@ config CC_HAS_IBT
config X86_KERNEL_IBT
prompt "Indirect Branch Tracking"
bool
- depends on X86_64 && CC_HAS_IBT && STACK_VALIDATION
+ depends on X86_64 && CC_HAS_IBT && HAVE_OBJTOOL
# https://github.com/llvm/llvm-project/commit/9d7001eba9c4cb311e03cd8cdc231f9e579f2d0f
depends on !LD_IS_LLD || LLD_VERSION >= 140000
+ select OBJTOOL
help
Build the kernel with support for Indirect Branch Tracking, a
hardware support course-grain forward-edge Control Flow Integrity
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index d3a6f74a94bd..d872a7522e55 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -237,7 +237,7 @@ choice
config UNWINDER_ORC
bool "ORC unwinder"
depends on X86_64
- select STACK_VALIDATION
+ select OBJTOOL
help
This option enables the ORC (Oops Rewind Capability) unwinder for
unwinding kernel stack traces. It uses a custom data format which is
diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h
index 0449b125d27f..3ce0e67c579c 100644
--- a/arch/x86/include/asm/jump_label.h
+++ b/arch/x86/include/asm/jump_label.h
@@ -20,7 +20,7 @@
_ASM_PTR "%c0 + %c1 - .\n\t" \
".popsection \n\t"

-#ifdef CONFIG_STACK_VALIDATION
+#ifdef CONFIG_OBJTOOL

static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
{
@@ -34,7 +34,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran
return true;
}

-#else
+#else /* !CONFIG_OBJTOOL */

static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch)
{
@@ -48,7 +48,7 @@ static __always_inline bool arch_static_branch(struct static_key * const key, co
return true;
}

-#endif /* STACK_VALIDATION */
+#endif /* CONFIG_OBJTOOL */

static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch)
{
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index d374cb3cf024..3c66073e7645 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -338,7 +338,7 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start,
}
}

-#if defined(CONFIG_RETPOLINE) && defined(CONFIG_STACK_VALIDATION)
+#if defined(CONFIG_RETPOLINE) && defined(CONFIG_OBJTOOL)

/*
* CALL/JMP *%\reg
@@ -507,11 +507,11 @@ void __init_or_module noinline apply_retpolines(s32 *start, s32 *end)
}
}

-#else /* !RETPOLINES || !CONFIG_STACK_VALIDATION */
+#else /* !CONFIG_RETPOLINE || !CONFIG_OBJTOOL */

void __init_or_module noinline apply_retpolines(s32 *start, s32 *end) { }

-#endif /* CONFIG_RETPOLINE && CONFIG_STACK_VALIDATION */
+#endif /* CONFIG_RETPOLINE && CONFIG_OBJTOOL */

#ifdef CONFIG_X86_KERNEL_IBT

diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 219aa5ddbc73..01ce94b58b42 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -109,7 +109,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
#endif

/* Unreachable code */
-#ifdef CONFIG_STACK_VALIDATION
+#ifdef CONFIG_OBJTOOL
/*
* These macros help objtool understand GCC code flow for unreachable code.
* The __COUNTER__ based labels are a hack to make each instance of the macros
@@ -128,10 +128,10 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
/* Annotate a C jump table to allow objtool to follow the code flow */
#define __annotate_jump_table __section(".rodata..c_jump_table")

-#else
+#else /* !CONFIG_OBJTOOL */
#define annotate_unreachable()
#define __annotate_jump_table
-#endif
+#endif /* CONFIG_OBJTOOL */

#ifndef unreachable
# define unreachable() do { \
diff --git a/include/linux/instrumentation.h b/include/linux/instrumentation.h
index 24359b4a9605..9111a3704072 100644
--- a/include/linux/instrumentation.h
+++ b/include/linux/instrumentation.h
@@ -2,7 +2,7 @@
#ifndef __LINUX_INSTRUMENTATION_H
#define __LINUX_INSTRUMENTATION_H

-#if defined(CONFIG_DEBUG_ENTRY) && defined(CONFIG_STACK_VALIDATION)
+#ifdef CONFIG_VMLINUX_VALIDATION

#include <linux/stringify.h>

@@ -53,9 +53,9 @@
".popsection\n\t" : : "i" (c)); \
})
#define instrumentation_end() __instrumentation_end(__COUNTER__)
-#else
+#else /* !CONFIG_VMLINUX_VALIDATION */
# define instrumentation_begin() do { } while(0)
# define instrumentation_end() do { } while(0)
-#endif
+#endif /* CONFIG_VMLINUX_VALIDATION */

#endif /* __LINUX_INSTRUMENTATION_H */
diff --git a/include/linux/objtool.h b/include/linux/objtool.h
index 586d35720f13..977d90ba642d 100644
--- a/include/linux/objtool.h
+++ b/include/linux/objtool.h
@@ -38,7 +38,7 @@ struct unwind_hint {
#define UNWIND_HINT_TYPE_REGS_PARTIAL 2
#define UNWIND_HINT_TYPE_FUNC 3

-#ifdef CONFIG_STACK_VALIDATION
+#ifdef CONFIG_OBJTOOL

#ifndef __ASSEMBLY__

@@ -157,7 +157,7 @@ struct unwind_hint {

#endif /* __ASSEMBLY__ */

-#else /* !CONFIG_STACK_VALIDATION */
+#else /* !CONFIG_OBJTOOL */

#ifndef __ASSEMBLY__

@@ -179,6 +179,6 @@ struct unwind_hint {
.endm
#endif

-#endif /* CONFIG_STACK_VALIDATION */
+#endif /* CONFIG_OBJTOOL */

#endif /* _LINUX_OBJTOOL_H */
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 2c43e327a619..2956bc277150 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -728,6 +728,7 @@ config FTRACE_MCOUNT_USE_OBJTOOL
depends on !FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY
depends on !FTRACE_MCOUNT_USE_CC
depends on FTRACE_MCOUNT_RECORD
+ select OBJTOOL

config FTRACE_MCOUNT_USE_RECORDMCOUNT
def_bool y
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 075cd25363ac..c0e4e47f3ce3 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -485,24 +485,25 @@ config FRAME_POINTER
larger and slower, but it gives very useful debugging information
in case of kernel bugs. (precise oopses/stacktraces/warnings)

+config OBJTOOL
+ bool
+
config STACK_VALIDATION
bool "Compile-time stack metadata validation"
- depends on HAVE_STACK_VALIDATION
+ depends on HAVE_STACK_VALIDATION && UNWINDER_FRAME_POINTER
+ select OBJTOOL
default n
help
- Add compile-time checks to validate stack metadata, including frame
- pointers (if CONFIG_FRAME_POINTER is enabled). This helps ensure
- that runtime stack traces are more reliable.
-
- This is also a prerequisite for generation of ORC unwind data, which
- is needed for CONFIG_UNWINDER_ORC.
+ Validate frame pointer rules at compile-time. This helps ensure that
+ runtime stack traces are more reliable.

For more information, see
tools/objtool/Documentation/stack-validation.txt.

config VMLINUX_VALIDATION
bool
- depends on STACK_VALIDATION && DEBUG_ENTRY
+ depends on HAVE_OBJTOOL && DEBUG_ENTRY
+ select OBJTOOL
default y

config VMLINUX_MAP
@@ -2035,10 +2036,11 @@ config KCOV
bool "Code coverage for fuzzing"
depends on ARCH_HAS_KCOV
depends on CC_HAS_SANCOV_TRACE_PC || GCC_PLUGINS
- depends on !ARCH_WANTS_NO_INSTR || STACK_VALIDATION || \
+ depends on !ARCH_WANTS_NO_INSTR || HAVE_OBJTOOL || \
GCC_VERSION >= 120000 || CLANG_VERSION >= 130000
select DEBUG_FS
select GCC_PLUGIN_SANCOV if !CC_HAS_SANCOV_TRACE_PC
+ select OBJTOOL if HAVE_OBJTOOL
help
KCOV exposes kernel code coverage information in a form suitable
for coverage-guided fuzzing (randomized testing).
diff --git a/lib/Kconfig.kcsan b/lib/Kconfig.kcsan
index de022445fbba..901c3b509aca 100644
--- a/lib/Kconfig.kcsan
+++ b/lib/Kconfig.kcsan
@@ -187,7 +187,8 @@ config KCSAN_WEAK_MEMORY
# We can either let objtool nop __tsan_func_{entry,exit}() and builtin
# atomics instrumentation in .noinstr.text, or use a compiler that can
# implement __no_kcsan to really remove all instrumentation.
- depends on STACK_VALIDATION || CC_IS_GCC || CLANG_VERSION >= 140000
+ depends on HAVE_OBJTOOL || CC_IS_GCC || CLANG_VERSION >= 140000
+ select OBJTOOL if HAVE_OBJTOOL
help
Enable support for modeling a subset of weak memory, which allows
detecting a subset of data races due to missing memory barriers.
diff --git a/lib/Kconfig.ubsan b/lib/Kconfig.ubsan
index f3c57ed51838..c4fe15d38b60 100644
--- a/lib/Kconfig.ubsan
+++ b/lib/Kconfig.ubsan
@@ -94,7 +94,7 @@ config UBSAN_UNREACHABLE
bool "Perform checking for unreachable code"
# objtool already handles unreachable checking and gets angry about
# seeing UBSan instrumentation located in unreachable places.
- depends on !STACK_VALIDATION
+ depends on !(OBJTOOL && (STACK_VALIDATION || UNWINDER_ORC || X86_SMAP))
depends on $(cc-option,-fsanitize=unreachable)
help
This option enables -fsanitize=unreachable which checks for control
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index d5e15ae29156..0f73e02b7cf1 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -222,7 +222,7 @@ cmd_record_mcount = $(if $(findstring $(strip $(CC_FLAGS_FTRACE)),$(_c_flags)),
$(sub_cmd_record_mcount))
endif # CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT

-ifdef CONFIG_STACK_VALIDATION
+ifdef CONFIG_OBJTOOL

objtool := $(objtree)/tools/objtool/objtool

@@ -241,7 +241,7 @@ objtool_args = \
cmd_objtool = $(if $(objtool-enabled), ; $(objtool) $(objtool_args) $@)
cmd_gen_objtooldep = $(if $(objtool-enabled), { echo ; echo '$@: $$(wildcard $(objtool))' ; } >> $(dot-target).cmd)

-endif # CONFIG_STACK_VALIDATION
+endif # CONFIG_OBJTOOL

ifneq ($(CONFIG_LTO_CLANG)$(CONFIG_X86_KERNEL_IBT),)

diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 0140bfa32c0c..5101a7fbfaaf 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -108,8 +108,11 @@ objtool_link()
local objtoolcmd;
local objtoolopt;

- if is_enabled CONFIG_STACK_VALIDATION && \
- ( is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT ); then
+ if ! is_enabled CONFIG_OBJTOOL; then
+ return;
+ fi
+
+ if is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT; then

# Don't perform vmlinux validation unless explicitly requested,
# but run objtool on vmlinux.o now that we have an object file.
@@ -126,10 +129,23 @@ objtool_link()
objtoolopt="${objtoolopt} --orc"
fi

+ if is_enabled CONFIG_RETPOLINE; then
+ objtoolopt="${objtoolopt} --retpoline"
+ fi
+
+ if is_enabled CONFIG_SLS; then
+ objtoolopt="${objtoolopt} --sls"
+ fi
+
if is_enabled CONFIG_STACK_VALIDATION; then
objtoolopt="${objtoolopt} --stackval"
fi

+ if is_enabled CONFIG_X86_SMAP; then
+ objtoolopt="${objtoolopt} --uaccess"
+ fi
+
+
objtoolopt="${objtoolopt} --lto"
fi

@@ -139,18 +155,6 @@ objtool_link()

if [ -n "${objtoolopt}" ]; then

- if is_enabled CONFIG_RETPOLINE; then
- objtoolopt="${objtoolopt} --retpoline"
- fi
-
- if is_enabled CONFIG_SLS; then
- objtoolopt="${objtoolopt} --sls"
- fi
-
- if is_enabled CONFIG_X86_SMAP; then
- objtoolopt="${objtoolopt} --uaccess"
- fi
-
if ! is_enabled CONFIG_FRAME_POINTER; then
objtoolopt="${objtoolopt} --no-fp"
fi
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
index 91a502bb97e8..67cd420dcf89 100755
--- a/scripts/package/builddeb
+++ b/scripts/package/builddeb
@@ -67,7 +67,7 @@ deploy_kernel_headers () {
) > debian/hdrsrcfiles

{
- if is_enabled CONFIG_STACK_VALIDATION; then
+ if is_enabled CONFIG_OBJTOOL; then
echo tools/objtool/objtool
fi

diff --git a/tools/include/linux/objtool.h b/tools/include/linux/objtool.h
index 586d35720f13..977d90ba642d 100644
--- a/tools/include/linux/objtool.h
+++ b/tools/include/linux/objtool.h
@@ -38,7 +38,7 @@ struct unwind_hint {
#define UNWIND_HINT_TYPE_REGS_PARTIAL 2
#define UNWIND_HINT_TYPE_FUNC 3

-#ifdef CONFIG_STACK_VALIDATION
+#ifdef CONFIG_OBJTOOL

#ifndef __ASSEMBLY__

@@ -157,7 +157,7 @@ struct unwind_hint {

#endif /* __ASSEMBLY__ */

-#else /* !CONFIG_STACK_VALIDATION */
+#else /* !CONFIG_OBJTOOL */

#ifndef __ASSEMBLY__

@@ -179,6 +179,6 @@ struct unwind_hint {
.endm
#endif

-#endif /* CONFIG_STACK_VALIDATION */
+#endif /* CONFIG_OBJTOOL */

#endif /* _LINUX_OBJTOOL_H */
--
2.34.1

2022-04-22 00:20:30

by Miroslav Benes

[permalink] [raw]
Subject: Re: [PATCH v2 00/25] objtool: Interface overhaul

> $ tools/objtool/objtool --help
>
> Usage: objtool <actions> [<options>] file.o
>
> Actions:
> -h, --hacks[=<jump_label,noinstr>]
> patch toolchain bugs/limitations
> -i, --ibt validate and annotate IBT
> -l, --sls validate straight-line-speculation mitigations
> -m, --mcount annotate mcount/fentry calls for ftrace
> -n, --noinstr validate noinstr rules
> -o, --orc generate ORC metadata
> -r, --retpoline validate and annotate retpoline usage
> -s, --stackval validate frame pointer rules
> -t, --static-call annotate static calls
> -u, --uaccess validate uaccess rules for SMAP
> --dump[=<orc>] dump metadata
>
> Options:
> --backtrace unwind on error
> --backup create .orig files before modification
> --dry-run don't write modifications
> --link object is a linked object
> --module object is part of a kernel module
> --no-unreachable skip 'unreachable instruction' warnings
> --sec-address print section addresses in warnings
> --stats print statistics

Nice job! The outcome is much clearer now.

Reviewed-by: Miroslav Benes <[email protected]>

M

2022-04-22 02:00:33

by Josh Poimboeuf

[permalink] [raw]
Subject: [PATCH v2 02/25] libsubcmd: Fix OPTION_GROUP sorting

The OPTION_GROUP option type is a way of grouping certain options
together in the printed usage text. It happens to be completely broken,
thanks to the fact that the subcmd option sorting just sorts everything,
without regard for grouping. Luckily, nobody uses this option anyway,
though that will change shortly.

Fix it by sorting each group individually.

Signed-off-by: Josh Poimboeuf <[email protected]>
---
tools/lib/subcmd/parse-options.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/tools/lib/subcmd/parse-options.c b/tools/lib/subcmd/parse-options.c
index 39ebf6192016..9fa75943f2ed 100644
--- a/tools/lib/subcmd/parse-options.c
+++ b/tools/lib/subcmd/parse-options.c
@@ -806,9 +806,9 @@ static int option__cmp(const void *va, const void *vb)

static struct option *options__order(const struct option *opts)
{
- int nr_opts = 0, len;
+ int nr_opts = 0, nr_group = 0, len;
const struct option *o = opts;
- struct option *ordered;
+ struct option *opt, *ordered, *group;

for (o = opts; o->type != OPTION_END; o++)
++nr_opts;
@@ -819,7 +819,18 @@ static struct option *options__order(const struct option *opts)
goto out;
memcpy(ordered, opts, len);

- qsort(ordered, nr_opts, sizeof(*o), option__cmp);
+ /* sort each option group individually */
+ for (opt = group = ordered; opt->type != OPTION_END; opt++) {
+ if (opt->type == OPTION_GROUP) {
+ qsort(group, nr_group, sizeof(*opt), option__cmp);
+ group = opt + 1;
+ nr_group = 0;
+ continue;
+ }
+ nr_group++;
+ }
+ qsort(group, nr_group, sizeof(*opt), option__cmp);
+
out:
return ordered;
}
--
2.34.1

2022-04-22 07:27:00

by Josh Poimboeuf

[permalink] [raw]
Subject: [PATCH v2 20/25] objtool: Make jump label hack optional

Objtool secretly does a jump label hack to overcome the limitations of
the toolchain. Make the hack explicit (and optional for other arches)
by turning it into a cmdline option and kernel config option.

Signed-off-by: Josh Poimboeuf <[email protected]>
---
arch/Kconfig | 4 +++
arch/x86/Kconfig | 1 +
arch/x86/include/asm/jump_label.h | 6 ++--
scripts/Makefile.build | 1 +
scripts/link-vmlinux.sh | 4 +++
tools/objtool/builtin-check.c | 37 +++++++++++++++++++------
tools/objtool/check.c | 2 +-
tools/objtool/include/objtool/builtin.h | 1 +
8 files changed, 44 insertions(+), 12 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index 04cdef16db24..9dce6d6e3bc3 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -46,6 +46,7 @@ config JUMP_LABEL
bool "Optimize very unlikely/likely branches"
depends on HAVE_ARCH_JUMP_LABEL
depends on CC_HAS_ASM_GOTO
+ select OBJTOOL if HAVE_JUMP_LABEL_HACK
help
This option enables a transparent branch optimization that
makes certain almost-always-true or almost-always-false branch
@@ -1031,6 +1032,9 @@ config ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
config HAVE_OBJTOOL
bool

+config HAVE_JUMP_LABEL_HACK
+ bool
+
config HAVE_STACK_VALIDATION
bool
help
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index bce0c23f3550..46218967129f 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -212,6 +212,7 @@ config X86
select HAVE_IOREMAP_PROT
select HAVE_IRQ_EXIT_ON_IRQ_STACK if X86_64
select HAVE_IRQ_TIME_ACCOUNTING
+ select HAVE_JUMP_LABEL_HACK if HAVE_OBJTOOL
select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_LZ4
diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h
index 3ce0e67c579c..071572e23d3a 100644
--- a/arch/x86/include/asm/jump_label.h
+++ b/arch/x86/include/asm/jump_label.h
@@ -20,7 +20,7 @@
_ASM_PTR "%c0 + %c1 - .\n\t" \
".popsection \n\t"

-#ifdef CONFIG_OBJTOOL
+#ifdef CONFIG_HAVE_JUMP_LABEL_HACK

static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
{
@@ -34,7 +34,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran
return true;
}

-#else /* !CONFIG_OBJTOOL */
+#else /* !CONFIG_HAVE_JUMP_LABEL_HACK */

static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch)
{
@@ -48,7 +48,7 @@ static __always_inline bool arch_static_branch(struct static_key * const key, co
return true;
}

-#endif /* CONFIG_OBJTOOL */
+#endif /* CONFIG_HAVE_JUMP_LABEL_HACK */

static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch)
{
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 3f20d565733c..f1d2c2e4f15b 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -227,6 +227,7 @@ ifdef CONFIG_OBJTOOL
objtool := $(objtree)/tools/objtool/objtool

objtool_args = \
+ $(if $(CONFIG_HAVE_JUMP_LABEL_HACK), --hacks=jump_label) \
$(if $(CONFIG_X86_KERNEL_IBT), --lto --ibt) \
$(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \
$(if $(CONFIG_UNWINDER_ORC), --orc) \
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 33f14fe1ddde..fa1f16840e76 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -117,6 +117,10 @@ objtool_link()
# Don't perform vmlinux validation unless explicitly requested,
# but run objtool on vmlinux.o now that we have an object file.

+ if is_enabled CONFIG_HAVE_JUMP_LABEL_HACK; then
+ objtoolopt="${objtoolopt} --hacks=jump_label"
+ fi
+
if is_enabled CONFIG_X86_KERNEL_IBT; then
objtoolopt="${objtoolopt} --ibt"
fi
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index c8c4d2bab42f..b2c626d9e2bf 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -31,8 +31,28 @@ static int parse_dump(const struct option *opt, const char *str, int unset)
return -1;
}

+static int parse_hacks(const struct option *opt, const char *str, int unset)
+{
+ bool found = false;
+
+ /*
+ * Use strstr() as a lazy method of checking for comma-separated
+ * options.
+ *
+ * No string provided == enable all options.
+ */
+
+ if (!str || strstr(str, "jump_label")) {
+ opts.hack_jump_label = true;
+ found = true;
+ }
+
+ return found ? 0 : -1;
+}
+
const struct option check_options[] = {
OPT_GROUP("Actions:"),
+ OPT_CALLBACK_OPTARG('h', "hacks", NULL, NULL, "jump_label", "patch toolchain bugs/limitations", parse_hacks),
OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"),
OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls for ftrace"),
OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"),
@@ -87,14 +107,15 @@ int cmd_parse_options(int argc, const char **argv, const char * const usage[])

static bool opts_valid(void)
{
- if (opts.ibt ||
- opts.mcount ||
- opts.noinstr ||
- opts.orc ||
- opts.retpoline ||
- opts.sls ||
- opts.stackval ||
- opts.static_call ||
+ if (opts.hack_jump_label ||
+ opts.ibt ||
+ opts.mcount ||
+ opts.noinstr ||
+ opts.orc ||
+ opts.retpoline ||
+ opts.sls ||
+ opts.stackval ||
+ opts.static_call ||
opts.uaccess) {
if (opts.dump_orc) {
fprintf(stderr, "--dump can't be combined with other options\n");
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index ffb843ef372d..eb3dffab8767 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1593,7 +1593,7 @@ static int handle_jump_alt(struct objtool_file *file,
return -1;
}

- if (special_alt->key_addend & 2) {
+ if (opts.hack_jump_label && special_alt->key_addend & 2) {
struct reloc *reloc = insn_reloc(file, orig_insn);

if (reloc) {
diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h
index dc4757205b8d..c6acf05ec859 100644
--- a/tools/objtool/include/objtool/builtin.h
+++ b/tools/objtool/include/objtool/builtin.h
@@ -12,6 +12,7 @@ extern const struct option check_options[];
struct opts {
/* actions: */
bool dump_orc;
+ bool hack_jump_label;
bool ibt;
bool mcount;
bool noinstr;
--
2.34.1

2022-04-22 10:31:12

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [PATCH v2 06/25] x86/xen: Add ANNOTATE_ENDBR to startup_xen()

On Tue, Apr 19, 2022 at 11:42:12AM +0000, Andrew Cooper wrote:
> On 18/04/2022 17:50, Josh Poimboeuf wrote:
> > The startup_xen() kernel entry point is referenced by the ".note.Xen"
> > section, but is presumably not indirect-branched to.
>
> It's the real entrypoint of the VM.? It's "got to" by setting %rip
> during vcpu setup.
>
> We could in principle support starting a PV VM with CET active, but that
> sounds like an enormous quantity of effort for very little gain.? CET
> for Xen PV requires paravirt anyway (because the kernel runs in CPL!=0)
> so decisions like this can wait until someone feels like doing the work.
>
> > Add ANNOTATE_ENDBR
> > to silence future objtool warnings.
> >
> > Cc: Boris Ostrovsky <[email protected]>
> > Cc: Juergen Gross <[email protected]>
> > Cc: Stefano Stabellini <[email protected]>
> > Cc: [email protected]
> > Signed-off-by: Josh Poimboeuf <[email protected]>
>
> FWIW, Reviewed-by: Andrew Cooper <[email protected]>, preferably
> with the commit message tweaked to remove the uncertainty.

Something like so then?

---
Subject: x86/xen: Add ANNOTATE_ENDBR to startup_xen()
From: Josh Poimboeuf <[email protected]>
Date: Mon, 18 Apr 2022 09:50:25 -0700

From: Josh Poimboeuf <[email protected]>

The startup_xen() kernel entry point is referenced by the ".note.Xen"
section, and is the real entry point of the VM. It *will* be
indirectly branched to, *however* currently Xen doesn't support PV VM
with CET active.

Add ANNOTATE_ENDBR to silence future objtool warnings.

Fixes: ed53a0d97192 ("x86/alternative: Use .ibt_endbr_seal to seal indirect calls")
Signed-off-by: Josh Poimboeuf <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
Reviewed-by: Andrew Cooper <[email protected]>
Link: https://lkml.kernel.org/r/a87bd48b06d11ec4b98122a429e71e489b4e48c3.1650300597.git.jpoimboe@redhat.com

Subject: [tip: objtool/core] objtool: Remove --lto and --vmlinux in favor of --link

The following commit has been merged into the objtool/core branch of tip:

Commit-ID: 753da4179d08b625d8df72e97724e22749969fd3
Gitweb: https://git.kernel.org/tip/753da4179d08b625d8df72e97724e22749969fd3
Author: Josh Poimboeuf <[email protected]>
AuthorDate: Mon, 18 Apr 2022 09:50:43 -07:00
Committer: Peter Zijlstra <[email protected]>
CommitterDate: Fri, 22 Apr 2022 12:32:05 +02:00

objtool: Remove --lto and --vmlinux in favor of --link

The '--lto' option is a confusing way of telling objtool to do stack
validation despite it being a linked object. It's no longer needed now
that an explicit '--stackval' option exists. The '--vmlinux' option is
also redundant.

Remove both options in favor of a straightforward '--link' option which
identifies a linked object.

Also, implicitly set '--link' with a warning if the user forgets to do
so and we can tell that it's a linked object. This makes it easier for
manual vmlinux runs.

Signed-off-by: Josh Poimboeuf <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
Reviewed-by: Miroslav Benes <[email protected]>
Link: https://lkml.kernel.org/r/dcd3ceffd15a54822c6183e5766d21ad06082b45.1650300597.git.jpoimboe@redhat.com
---
scripts/Makefile.build | 4 +-
scripts/link-vmlinux.sh | 8 +----
tools/objtool/builtin-check.c | 39 ++++++++++++++++++++---
tools/objtool/check.c | 40 ++++++++----------------
tools/objtool/elf.c | 3 ++-
tools/objtool/include/objtool/builtin.h | 3 +--
tools/objtool/include/objtool/elf.h | 12 ++++++-
7 files changed, 70 insertions(+), 39 deletions(-)

diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 6c206a1..ac81672 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -229,7 +229,7 @@ objtool := $(objtree)/tools/objtool/objtool
objtool_args = \
$(if $(CONFIG_HAVE_JUMP_LABEL_HACK), --hacks=jump_label) \
$(if $(CONFIG_HAVE_NOINSTR_HACK), --hacks=noinstr) \
- $(if $(CONFIG_X86_KERNEL_IBT), --lto --ibt) \
+ $(if $(CONFIG_X86_KERNEL_IBT), --ibt) \
$(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \
$(if $(CONFIG_UNWINDER_ORC), --orc) \
$(if $(CONFIG_RETPOLINE), --retpoline) \
@@ -237,6 +237,7 @@ objtool_args = \
$(if $(CONFIG_STACK_VALIDATION), --stackval) \
$(if $(CONFIG_HAVE_STATIC_CALL_INLINE), --static-call) \
$(if $(CONFIG_X86_SMAP), --uaccess) \
+ $(if $(linked-object), --link) \
$(if $(part-of-module), --module) \
$(if $(CONFIG_GCOV_KERNEL), --no-unreachable)

@@ -306,6 +307,7 @@ quiet_cmd_cc_prelink_modules = LD [M] $@
# modules into native code
$(obj)/%.prelink.o: objtool-enabled = y
$(obj)/%.prelink.o: part-of-module := y
+$(obj)/%.prelink.o: linked-object := y

$(obj)/%.prelink.o: $(obj)/%.o FORCE
$(call if_changed,cc_prelink_modules)
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index fce4f41..eb9324f 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -114,8 +114,8 @@ objtool_link()

if is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT; then

- # Don't perform vmlinux validation unless explicitly requested,
- # but run objtool on vmlinux.o now that we have an object file.
+ # For LTO and IBT, objtool doesn't run on individual
+ # translation units. Run everything on vmlinux instead.

if is_enabled CONFIG_HAVE_JUMP_LABEL_HACK; then
objtoolopt="${objtoolopt} --hacks=jump_label"
@@ -156,8 +156,6 @@ objtool_link()
if is_enabled CONFIG_X86_SMAP; then
objtoolopt="${objtoolopt} --uaccess"
fi
-
- objtoolopt="${objtoolopt} --lto"
fi

if is_enabled CONFIG_NOINSTR_VALIDATION; then
@@ -170,7 +168,7 @@ objtool_link()
objtoolopt="${objtoolopt} --no-unreachable"
fi

- objtoolopt="${objtoolopt} --vmlinux"
+ objtoolopt="${objtoolopt} --link"

info OBJTOOL ${1}
tools/objtool/objtool ${objtoolopt} ${1}
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index 1803a63..f4c3a50 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -9,6 +9,11 @@
#include <objtool/builtin.h>
#include <objtool/objtool.h>

+#define ERROR(format, ...) \
+ fprintf(stderr, \
+ "error: objtool: " format "\n", \
+ ##__VA_ARGS__)
+
struct opts opts;

static const char * const check_usage[] = {
@@ -73,12 +78,11 @@ const struct option check_options[] = {
OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"),
OPT_BOOLEAN(0, "backup", &opts.backup, "create .orig files before modification"),
OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"),
- OPT_BOOLEAN(0, "lto", &opts.lto, "whole-archive like runs"),
+ OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"),
OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"),
OPT_BOOLEAN(0, "no-unreachable", &opts.no_unreachable, "skip 'unreachable instruction' warnings"),
OPT_BOOLEAN(0, "sec-address", &opts.sec_address, "print section addresses in warnings"),
OPT_BOOLEAN(0, "stats", &opts.stats, "print statistics"),
- OPT_BOOLEAN(0, "vmlinux", &opts.vmlinux, "vmlinux.o validation"),

OPT_END(),
};
@@ -124,7 +128,7 @@ static bool opts_valid(void)
opts.static_call ||
opts.uaccess) {
if (opts.dump_orc) {
- fprintf(stderr, "--dump can't be combined with other options\n");
+ ERROR("--dump can't be combined with other options");
return false;
}

@@ -134,10 +138,34 @@ static bool opts_valid(void)
if (opts.dump_orc)
return true;

- fprintf(stderr, "At least one command required\n");
+ ERROR("At least one command required");
return false;
}

+static bool link_opts_valid(struct objtool_file *file)
+{
+ if (opts.link)
+ return true;
+
+ if (has_multiple_files(file->elf)) {
+ ERROR("Linked object detected, forcing --link");
+ opts.link = true;
+ return true;
+ }
+
+ if (opts.noinstr) {
+ ERROR("--noinstr requires --link");
+ return false;
+ }
+
+ if (opts.ibt) {
+ ERROR("--ibt requires --link");
+ return false;
+ }
+
+ return true;
+}
+
int objtool_run(int argc, const char **argv)
{
const char *objname;
@@ -157,6 +185,9 @@ int objtool_run(int argc, const char **argv)
if (!file)
return 1;

+ if (!link_opts_valid(file))
+ return 1;
+
ret = check(file);
if (ret)
return ret;
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 30b24dc..2063f9f 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -263,7 +263,8 @@ static void init_cfi_state(struct cfi_state *cfi)
cfi->drap_offset = -1;
}

-static void init_insn_state(struct insn_state *state, struct section *sec)
+static void init_insn_state(struct objtool_file *file, struct insn_state *state,
+ struct section *sec)
{
memset(state, 0, sizeof(*state));
init_cfi_state(&state->cfi);
@@ -273,7 +274,7 @@ static void init_insn_state(struct insn_state *state, struct section *sec)
* not correctly determine insn->call_dest->sec (external symbols do
* not have a section).
*/
- if (opts.vmlinux && opts.noinstr && sec)
+ if (opts.link && opts.noinstr && sec)
state->noinstr = sec->noinstr;
}

@@ -3405,7 +3406,7 @@ static int validate_unwind_hints(struct objtool_file *file, struct section *sec)
if (!file->hints)
return 0;

- init_insn_state(&state, sec);
+ init_insn_state(file, &state, sec);

if (sec) {
insn = find_insn(file, sec, 0);
@@ -3491,14 +3492,14 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio
return true;

/*
- * Whole archive runs might encounder dead code from weak symbols.
+ * Whole archive runs might encounter dead code from weak symbols.
* This is where the linker will have dropped the weak symbol in
* favour of a regular symbol, but leaves the code in place.
*
* In this case we'll find a piece of code (whole function) that is not
* covered by a !section symbol. Ignore them.
*/
- if (!insn->func && opts.lto) {
+ if (opts.link && !insn->func) {
int size = find_symbol_hole_containing(insn->sec, insn->offset);
unsigned long end = insn->offset + size;

@@ -3620,7 +3621,7 @@ static int validate_section(struct objtool_file *file, struct section *sec)
if (func->type != STT_FUNC)
continue;

- init_insn_state(&state, sec);
+ init_insn_state(file, &state, sec);
set_func_state(&state.cfi);

warnings += validate_symbol(file, sec, func, &state);
@@ -3629,7 +3630,7 @@ static int validate_section(struct objtool_file *file, struct section *sec)
return warnings;
}

-static int validate_vmlinux_functions(struct objtool_file *file)
+static int validate_noinstr_sections(struct objtool_file *file)
{
struct section *sec;
int warnings = 0;
@@ -3890,16 +3891,6 @@ int check(struct objtool_file *file)
{
int ret, warnings = 0;

- if (opts.lto && !(opts.vmlinux || opts.module)) {
- fprintf(stderr, "--lto requires: --vmlinux or --module\n");
- return 1;
- }
-
- if (opts.ibt && !opts.lto) {
- fprintf(stderr, "--ibt requires: --lto\n");
- return 1;
- }
-
arch_initial_func_cfi_state(&initial_func_cfi);
init_cfi_state(&init_cfi);
init_cfi_state(&func_cfi);
@@ -3920,15 +3911,6 @@ int check(struct objtool_file *file)
if (list_empty(&file->insn_list))
goto out;

- if (opts.vmlinux && !opts.lto) {
- ret = validate_vmlinux_functions(file);
- if (ret < 0)
- goto out;
-
- warnings += ret;
- goto out;
- }
-
if (opts.retpoline) {
ret = validate_retpoline(file);
if (ret < 0)
@@ -3953,6 +3935,12 @@ int check(struct objtool_file *file)
goto out;
warnings += ret;
}
+
+ } else if (opts.noinstr) {
+ ret = validate_noinstr_sections(file);
+ if (ret < 0)
+ goto out;
+ warnings += ret;
}

if (opts.ibt) {
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 0f6fa37..583a3ec 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -377,6 +377,9 @@ static void elf_add_symbol(struct elf *elf, struct symbol *sym)
sym->type = GELF_ST_TYPE(sym->sym.st_info);
sym->bind = GELF_ST_BIND(sym->sym.st_info);

+ if (sym->type == STT_FILE)
+ elf->num_files++;
+
sym->offset = sym->sym.st_value;
sym->len = sym->sym.st_size;

diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h
index f3a1a75..280ea18 100644
--- a/tools/objtool/include/objtool/builtin.h
+++ b/tools/objtool/include/objtool/builtin.h
@@ -28,12 +28,11 @@ struct opts {
bool backtrace;
bool backup;
bool dryrun;
- bool lto;
+ bool link;
bool module;
bool no_unreachable;
bool sec_address;
bool stats;
- bool vmlinux;
};

extern struct opts opts;
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index 9b36802..de0cb2f 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -86,7 +86,7 @@ struct elf {
int fd;
bool changed;
char *name;
- unsigned int text_size;
+ unsigned int text_size, num_files;
struct list_head sections;

int symbol_bits;
@@ -131,6 +131,16 @@ static inline u32 reloc_hash(struct reloc *reloc)
return sec_offset_hash(reloc->sec, reloc->offset);
}

+/*
+ * Try to see if it's a whole archive (vmlinux.o or module).
+ *
+ * Note this will miss the case where a module only has one source file.
+ */
+static inline bool has_multiple_files(struct elf *elf)
+{
+ return elf->num_files > 1;
+}
+
struct elf *elf_open_read(const char *name, int flags);
struct section *elf_create_section(struct elf *elf, const char *name, unsigned int sh_flags, size_t entsize, int nr);

2022-04-22 18:23:26

by Josh Poimboeuf

[permalink] [raw]
Subject: [PATCH v2 16/25] objtool: Extricate sls from stack validation

Extricate sls functionality from validate_branch() so they can be
executed (or ported) independently from each other.

Signed-off-by: Josh Poimboeuf <[email protected]>
---
tools/objtool/check.c | 56 +++++++++++++++++++++++++++++++++----------
1 file changed, 43 insertions(+), 13 deletions(-)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 0059b592195e..88b527b3eb37 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -3272,11 +3272,6 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
switch (insn->type) {

case INSN_RETURN:
- if (opts.sls && !insn->retpoline_safe &&
- next_insn && next_insn->type != INSN_TRAP) {
- WARN_FUNC("missing int3 after ret",
- insn->sec, insn->offset);
- }
return validate_return(func, insn, &state);

case INSN_CALL:
@@ -3320,13 +3315,6 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
break;

case INSN_JUMP_DYNAMIC:
- if (opts.sls && !insn->retpoline_safe &&
- next_insn && next_insn->type != INSN_TRAP) {
- WARN_FUNC("missing int3 after indirect jump",
- insn->sec, insn->offset);
- }
-
- /* fallthrough */
case INSN_JUMP_DYNAMIC_CONDITIONAL:
if (is_sibling_call(insn)) {
ret = validate_sibling_call(file, insn, &state);
@@ -3846,6 +3834,41 @@ static int validate_ibt(struct objtool_file *file)
return warnings;
}

+static int validate_sls(struct objtool_file *file)
+{
+ struct instruction *insn, *next_insn;
+ int warnings = 0;
+
+ for_each_insn(file, insn) {
+ next_insn = next_insn_same_sec(file, insn);
+
+ if (insn->retpoline_safe)
+ continue;
+
+ switch (insn->type) {
+ case INSN_RETURN:
+ if (!next_insn || next_insn->type != INSN_TRAP) {
+ WARN_FUNC("missing int3 after ret",
+ insn->sec, insn->offset);
+ warnings++;
+ }
+
+ break;
+ case INSN_JUMP_DYNAMIC:
+ if (!next_insn || next_insn->type != INSN_TRAP) {
+ WARN_FUNC("missing int3 after indirect jump",
+ insn->sec, insn->offset);
+ warnings++;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return warnings;
+}
+
static int validate_reachable_instructions(struct objtool_file *file)
{
struct instruction *insn;
@@ -3914,7 +3937,7 @@ int check(struct objtool_file *file)
warnings += ret;
}

- if (opts.stackval || opts.orc || opts.uaccess || opts.sls) {
+ if (opts.stackval || opts.orc || opts.uaccess) {
ret = validate_functions(file);
if (ret < 0)
goto out;
@@ -3940,6 +3963,13 @@ int check(struct objtool_file *file)
warnings += ret;
}

+ if (opts.sls) {
+ ret = validate_sls(file);
+ if (ret < 0)
+ goto out;
+ warnings += ret;
+ }
+
ret = create_static_call_sections(file);
if (ret < 0)
goto out;
--
2.34.1

2022-04-22 18:50:24

by Josh Poimboeuf

[permalink] [raw]
Subject: [PATCH v2 18/25] objtool: Make stack validation frame-pointer-specific

Now that CONFIG_STACK_VALIDATION is frame-pointer specific, do the same
for the '--stackval' option. Now the '--no-fp' option is redundant and
can be removed.

Signed-off-by: Josh Poimboeuf <[email protected]>
---
scripts/Makefile.build | 1 -
scripts/link-vmlinux.sh | 4 ----
tools/objtool/builtin-check.c | 3 +--
tools/objtool/check.c | 4 ++--
tools/objtool/include/objtool/builtin.h | 1 -
5 files changed, 3 insertions(+), 10 deletions(-)

diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 0f73e02b7cf1..6eb99cb08821 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -235,7 +235,6 @@ objtool_args = \
$(if $(CONFIG_STACK_VALIDATION), --stackval) \
$(if $(CONFIG_X86_SMAP), --uaccess) \
$(if $(part-of-module), --module) \
- $(if $(CONFIG_FRAME_POINTER),, --no-fp) \
$(if $(CONFIG_GCOV_KERNEL), --no-unreachable)

cmd_objtool = $(if $(objtool-enabled), ; $(objtool) $(objtool_args) $@)
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 5101a7fbfaaf..1be01163a9c5 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -155,10 +155,6 @@ objtool_link()

if [ -n "${objtoolopt}" ]; then

- if ! is_enabled CONFIG_FRAME_POINTER; then
- objtoolopt="${objtoolopt} --no-fp"
- fi
-
if is_enabled CONFIG_GCOV_KERNEL; then
objtoolopt="${objtoolopt} --no-unreachable"
fi
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index d4e6930ad0a0..30971cc50c63 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -39,7 +39,7 @@ const struct option check_options[] = {
OPT_BOOLEAN('o', "orc", &opts.orc, "generate ORC metadata"),
OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate retpoline usage"),
OPT_BOOLEAN('l', "sls", &opts.sls, "validate straight-line-speculation mitigations"),
- OPT_BOOLEAN('s', "stackval", &opts.stackval, "validate stack unwinding rules"),
+ OPT_BOOLEAN('s', "stackval", &opts.stackval, "validate frame pointer rules"),
OPT_BOOLEAN('u', "uaccess", &opts.uaccess, "validate uaccess rules for SMAP"),
OPT_CALLBACK_OPTARG(0, "dump", NULL, NULL, "orc", "dump metadata", parse_dump),

@@ -49,7 +49,6 @@ const struct option check_options[] = {
OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"),
OPT_BOOLEAN(0, "lto", &opts.lto, "whole-archive like runs"),
OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"),
- OPT_BOOLEAN(0, "no-fp", &opts.no_fp, "skip frame pointer validation"),
OPT_BOOLEAN(0, "no-unreachable", &opts.no_unreachable, "skip 'unreachable instruction' warnings"),
OPT_BOOLEAN(0, "sec-address", &opts.sec_address, "print section addresses in warnings"),
OPT_BOOLEAN(0, "stats", &opts.stats, "print statistics"),
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 88b527b3eb37..81688f6c46c0 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -2807,7 +2807,7 @@ static int update_cfi_state(struct instruction *insn,
}

/* detect when asm code uses rbp as a scratch register */
- if (!opts.no_fp && insn->func && op->src.reg == CFI_BP &&
+ if (opts.stackval && insn->func && op->src.reg == CFI_BP &&
cfa->base != CFI_BP)
cfi->bp_scratch = true;
break;
@@ -3280,7 +3280,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
if (ret)
return ret;

- if (!opts.no_fp && func && !is_fentry_call(insn) &&
+ if (opts.stackval && func && !is_fentry_call(insn) &&
!has_valid_stack_frame(&state)) {
WARN_FUNC("call without frame pointer save/setup",
sec, insn->offset);
diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h
index 8618585bb742..24a7ff4f37cc 100644
--- a/tools/objtool/include/objtool/builtin.h
+++ b/tools/objtool/include/objtool/builtin.h
@@ -27,7 +27,6 @@ struct opts {
bool dryrun;
bool lto;
bool module;
- bool no_fp;
bool no_unreachable;
bool sec_address;
bool stats;
--
2.34.1

Subject: [tip: objtool/core] objtool: Make jump label hack optional

The following commit has been merged into the objtool/core branch of tip:

Commit-ID: 4ab7674f5951ac6a8ac4fa8828090edb64a4771f
Gitweb: https://git.kernel.org/tip/4ab7674f5951ac6a8ac4fa8828090edb64a4771f
Author: Josh Poimboeuf <[email protected]>
AuthorDate: Mon, 18 Apr 2022 09:50:39 -07:00
Committer: Peter Zijlstra <[email protected]>
CommitterDate: Fri, 22 Apr 2022 12:32:04 +02:00

objtool: Make jump label hack optional

Objtool secretly does a jump label hack to overcome the limitations of
the toolchain. Make the hack explicit (and optional for other arches)
by turning it into a cmdline option and kernel config option.

Signed-off-by: Josh Poimboeuf <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
Reviewed-by: Miroslav Benes <[email protected]>
Link: https://lkml.kernel.org/r/3bdcbfdd27ecb01ddec13c04bdf756a583b13d24.1650300597.git.jpoimboe@redhat.com
---
arch/Kconfig | 4 +++-
arch/x86/Kconfig | 1 +-
arch/x86/include/asm/jump_label.h | 6 ++--
scripts/Makefile.build | 1 +-
scripts/link-vmlinux.sh | 4 +++-
tools/objtool/builtin-check.c | 37 ++++++++++++++++++------
tools/objtool/check.c | 2 +-
tools/objtool/include/objtool/builtin.h | 1 +-
8 files changed, 44 insertions(+), 12 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index 04cdef1..9dce6d6 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -46,6 +46,7 @@ config JUMP_LABEL
bool "Optimize very unlikely/likely branches"
depends on HAVE_ARCH_JUMP_LABEL
depends on CC_HAS_ASM_GOTO
+ select OBJTOOL if HAVE_JUMP_LABEL_HACK
help
This option enables a transparent branch optimization that
makes certain almost-always-true or almost-always-false branch
@@ -1031,6 +1032,9 @@ config ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
config HAVE_OBJTOOL
bool

+config HAVE_JUMP_LABEL_HACK
+ bool
+
config HAVE_STACK_VALIDATION
bool
help
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 43e26ee..26d012f 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -212,6 +212,7 @@ config X86
select HAVE_IOREMAP_PROT
select HAVE_IRQ_EXIT_ON_IRQ_STACK if X86_64
select HAVE_IRQ_TIME_ACCOUNTING
+ select HAVE_JUMP_LABEL_HACK if HAVE_OBJTOOL
select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_LZ4
diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h
index 3ce0e67..071572e 100644
--- a/arch/x86/include/asm/jump_label.h
+++ b/arch/x86/include/asm/jump_label.h
@@ -20,7 +20,7 @@
_ASM_PTR "%c0 + %c1 - .\n\t" \
".popsection \n\t"

-#ifdef CONFIG_OBJTOOL
+#ifdef CONFIG_HAVE_JUMP_LABEL_HACK

static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
{
@@ -34,7 +34,7 @@ l_yes:
return true;
}

-#else /* !CONFIG_OBJTOOL */
+#else /* !CONFIG_HAVE_JUMP_LABEL_HACK */

static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch)
{
@@ -48,7 +48,7 @@ l_yes:
return true;
}

-#endif /* CONFIG_OBJTOOL */
+#endif /* CONFIG_HAVE_JUMP_LABEL_HACK */

static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch)
{
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 3f20d56..f1d2c2e 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -227,6 +227,7 @@ ifdef CONFIG_OBJTOOL
objtool := $(objtree)/tools/objtool/objtool

objtool_args = \
+ $(if $(CONFIG_HAVE_JUMP_LABEL_HACK), --hacks=jump_label) \
$(if $(CONFIG_X86_KERNEL_IBT), --lto --ibt) \
$(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \
$(if $(CONFIG_UNWINDER_ORC), --orc) \
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 33f14fe..fa1f168 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -117,6 +117,10 @@ objtool_link()
# Don't perform vmlinux validation unless explicitly requested,
# but run objtool on vmlinux.o now that we have an object file.

+ if is_enabled CONFIG_HAVE_JUMP_LABEL_HACK; then
+ objtoolopt="${objtoolopt} --hacks=jump_label"
+ fi
+
if is_enabled CONFIG_X86_KERNEL_IBT; then
objtoolopt="${objtoolopt} --ibt"
fi
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index c8c4d2b..b2c626d 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -31,8 +31,28 @@ static int parse_dump(const struct option *opt, const char *str, int unset)
return -1;
}

+static int parse_hacks(const struct option *opt, const char *str, int unset)
+{
+ bool found = false;
+
+ /*
+ * Use strstr() as a lazy method of checking for comma-separated
+ * options.
+ *
+ * No string provided == enable all options.
+ */
+
+ if (!str || strstr(str, "jump_label")) {
+ opts.hack_jump_label = true;
+ found = true;
+ }
+
+ return found ? 0 : -1;
+}
+
const struct option check_options[] = {
OPT_GROUP("Actions:"),
+ OPT_CALLBACK_OPTARG('h', "hacks", NULL, NULL, "jump_label", "patch toolchain bugs/limitations", parse_hacks),
OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"),
OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls for ftrace"),
OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"),
@@ -87,14 +107,15 @@ int cmd_parse_options(int argc, const char **argv, const char * const usage[])

static bool opts_valid(void)
{
- if (opts.ibt ||
- opts.mcount ||
- opts.noinstr ||
- opts.orc ||
- opts.retpoline ||
- opts.sls ||
- opts.stackval ||
- opts.static_call ||
+ if (opts.hack_jump_label ||
+ opts.ibt ||
+ opts.mcount ||
+ opts.noinstr ||
+ opts.orc ||
+ opts.retpoline ||
+ opts.sls ||
+ opts.stackval ||
+ opts.static_call ||
opts.uaccess) {
if (opts.dump_orc) {
fprintf(stderr, "--dump can't be combined with other options\n");
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index b9ac351..d157978 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1592,7 +1592,7 @@ static int handle_jump_alt(struct objtool_file *file,
return -1;
}

- if (special_alt->key_addend & 2) {
+ if (opts.hack_jump_label && special_alt->key_addend & 2) {
struct reloc *reloc = insn_reloc(file, orig_insn);

if (reloc) {
diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h
index dc47572..c6acf05 100644
--- a/tools/objtool/include/objtool/builtin.h
+++ b/tools/objtool/include/objtool/builtin.h
@@ -12,6 +12,7 @@ extern const struct option check_options[];
struct opts {
/* actions: */
bool dump_orc;
+ bool hack_jump_label;
bool ibt;
bool mcount;
bool noinstr;

Subject: [tip: objtool/core] objtool: Extricate sls from stack validation

The following commit has been merged into the objtool/core branch of tip:

Commit-ID: c2bdd61c98d915ad2cc1f8cd4661fcda1f1e4c16
Gitweb: https://git.kernel.org/tip/c2bdd61c98d915ad2cc1f8cd4661fcda1f1e4c16
Author: Josh Poimboeuf <[email protected]>
AuthorDate: Mon, 18 Apr 2022 09:50:35 -07:00
Committer: Peter Zijlstra <[email protected]>
CommitterDate: Fri, 22 Apr 2022 12:32:03 +02:00

objtool: Extricate sls from stack validation

Extricate sls functionality from validate_branch() so they can be
executed (or ported) independently from each other.

Signed-off-by: Josh Poimboeuf <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
Reviewed-by: Miroslav Benes <[email protected]>
Link: https://lkml.kernel.org/r/2545c86ffa5f27497f0d0c542540ad4a4be3c5a5.1650300597.git.jpoimboe@redhat.com
---
tools/objtool/check.c | 56 ++++++++++++++++++++++++++++++++----------
1 file changed, 43 insertions(+), 13 deletions(-)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 85c2888..27126ff 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -3271,11 +3271,6 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
switch (insn->type) {

case INSN_RETURN:
- if (opts.sls && !insn->retpoline_safe &&
- next_insn && next_insn->type != INSN_TRAP) {
- WARN_FUNC("missing int3 after ret",
- insn->sec, insn->offset);
- }
return validate_return(func, insn, &state);

case INSN_CALL:
@@ -3319,13 +3314,6 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
break;

case INSN_JUMP_DYNAMIC:
- if (opts.sls && !insn->retpoline_safe &&
- next_insn && next_insn->type != INSN_TRAP) {
- WARN_FUNC("missing int3 after indirect jump",
- insn->sec, insn->offset);
- }
-
- /* fallthrough */
case INSN_JUMP_DYNAMIC_CONDITIONAL:
if (is_sibling_call(insn)) {
ret = validate_sibling_call(file, insn, &state);
@@ -3845,6 +3833,41 @@ static int validate_ibt(struct objtool_file *file)
return warnings;
}

+static int validate_sls(struct objtool_file *file)
+{
+ struct instruction *insn, *next_insn;
+ int warnings = 0;
+
+ for_each_insn(file, insn) {
+ next_insn = next_insn_same_sec(file, insn);
+
+ if (insn->retpoline_safe)
+ continue;
+
+ switch (insn->type) {
+ case INSN_RETURN:
+ if (!next_insn || next_insn->type != INSN_TRAP) {
+ WARN_FUNC("missing int3 after ret",
+ insn->sec, insn->offset);
+ warnings++;
+ }
+
+ break;
+ case INSN_JUMP_DYNAMIC:
+ if (!next_insn || next_insn->type != INSN_TRAP) {
+ WARN_FUNC("missing int3 after indirect jump",
+ insn->sec, insn->offset);
+ warnings++;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return warnings;
+}
+
static int validate_reachable_instructions(struct objtool_file *file)
{
struct instruction *insn;
@@ -3913,7 +3936,7 @@ int check(struct objtool_file *file)
warnings += ret;
}

- if (opts.stackval || opts.orc || opts.uaccess || opts.sls) {
+ if (opts.stackval || opts.orc || opts.uaccess) {
ret = validate_functions(file);
if (ret < 0)
goto out;
@@ -3939,6 +3962,13 @@ int check(struct objtool_file *file)
warnings += ret;
}

+ if (opts.sls) {
+ ret = validate_sls(file);
+ if (ret < 0)
+ goto out;
+ warnings += ret;
+ }
+
ret = create_static_call_sections(file);
if (ret < 0)
goto out;

2022-04-22 20:11:49

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [PATCH v2 17/25] objtool: Add CONFIG_OBJTOOL

On Mon, Apr 18, 2022 at 09:50:36AM -0700, Josh Poimboeuf wrote:

> config X86_SMAP
> def_bool y
> prompt "Supervisor Mode Access Prevention" if EXPERT
> + select OBJTOOL if HAVE_OBJTOOL
> help
> Supervisor Mode Access Prevention (SMAP) is a security
> feature in newer Intel processors. There is a small

Runs into:


commit dbae0a934f09208075ec3e73491bd0844e1397b3
Author: Borislav Petkov <[email protected]>
Date: Thu Jan 27 12:56:23 2022 +0100

x86/cpu: Remove CONFIG_X86_SMAP and "nosmap"

Those were added as part of the SMAP enablement but SMAP is currently
an integral part of kernel proper and there's no need to disable it
anymore.

Rip out that functionality. Leave --uaccess default on for objtool as
this is what objtool should do by default anyway.

If still needed - clearcpuid=smap.

Signed-off-by: Borislav Petkov <[email protected]>
Reviewed-by: Lai Jiangshan <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
Link: https://lore.kernel.org/r/[email protected]

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index a9f3d3158e77..e0bb710f0fa9 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -3461,7 +3461,7 @@
noexec=on: enable non-executable mappings (default)
noexec=off: disable non-executable mappings

- nosmap [X86,PPC]
+ nosmap [PPC]
Disable SMAP (Supervisor Mode Access Prevention)
even if it is supported by processor.

diff --git a/Documentation/x86/cpuinfo.rst b/Documentation/x86/cpuinfo.rst
index 5d54c39a063f..12fbe2b1e98a 100644
--- a/Documentation/x86/cpuinfo.rst
+++ b/Documentation/x86/cpuinfo.rst
@@ -140,9 +140,8 @@ from #define X86_FEATURE_UMIP (16*32 + 2).

In addition, there exists a variety of custom command-line parameters that
disable specific features. The list of parameters includes, but is not limited
-to, nofsgsbase, nosmap, and nosmep. 5-level paging can also be disabled using
-"no5lvl". SMAP and SMEP are disabled with the aforementioned parameters,
-respectively.
+to, nofsgsbase, and nosmep. 5-level paging can also be disabled using
+"no5lvl". SMEP is disabled with the aforementioned parameter.

e: The feature was known to be non-functional.
----------------------------------------------
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index b0142e01002e..5bc8bee64bb0 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1816,17 +1816,6 @@ config ARCH_RANDOM
If supported, this is a high bandwidth, cryptographically
secure hardware random number generator.

-config X86_SMAP
- def_bool y
- prompt "Supervisor Mode Access Prevention" if EXPERT
- help
- Supervisor Mode Access Prevention (SMAP) is a security
- feature in newer Intel processors. There is a small
- performance cost if this enabled and turned on; there is
- also a small increase in the kernel size if this is enabled.
-
- If unsure, say Y.
-
config X86_UMIP
def_bool y
prompt "User Mode Instruction Prevention" if EXPERT
diff --git a/arch/x86/include/asm/disabled-features.h b/arch/x86/include/asm/disabled-features.h
index 1231d63f836d..1ae0fab7d902 100644
--- a/arch/x86/include/asm/disabled-features.h
+++ b/arch/x86/include/asm/disabled-features.h
@@ -10,12 +10,6 @@
* cpu_feature_enabled().
*/

-#ifdef CONFIG_X86_SMAP
-# define DISABLE_SMAP 0
-#else
-# define DISABLE_SMAP (1<<(X86_FEATURE_SMAP & 31))
-#endif
-
#ifdef CONFIG_X86_UMIP
# define DISABLE_UMIP 0
#else
@@ -80,7 +74,7 @@
#define DISABLED_MASK6 0
#define DISABLED_MASK7 (DISABLE_PTI)
#define DISABLED_MASK8 0
-#define DISABLED_MASK9 (DISABLE_SMAP|DISABLE_SGX)
+#define DISABLED_MASK9 (DISABLE_SGX)
#define DISABLED_MASK10 0
#define DISABLED_MASK11 0
#define DISABLED_MASK12 0
diff --git a/arch/x86/include/asm/smap.h b/arch/x86/include/asm/smap.h
index d17b39893b79..bab490379c65 100644
--- a/arch/x86/include/asm/smap.h
+++ b/arch/x86/include/asm/smap.h
@@ -19,25 +19,14 @@

#ifdef __ASSEMBLY__

-#ifdef CONFIG_X86_SMAP
-
#define ASM_CLAC \
ALTERNATIVE "", __ASM_CLAC, X86_FEATURE_SMAP

#define ASM_STAC \
ALTERNATIVE "", __ASM_STAC, X86_FEATURE_SMAP

-#else /* CONFIG_X86_SMAP */
-
-#define ASM_CLAC
-#define ASM_STAC
-
-#endif /* CONFIG_X86_SMAP */
-
#else /* __ASSEMBLY__ */

-#ifdef CONFIG_X86_SMAP
-
static __always_inline void clac(void)
{
/* Note: a barrier is implicit in alternative() */
@@ -76,19 +65,6 @@ static __always_inline void smap_restore(unsigned long flags)
#define ASM_STAC \
ALTERNATIVE("", __ASM_STAC, X86_FEATURE_SMAP)

-#else /* CONFIG_X86_SMAP */
-
-static inline void clac(void) { }
-static inline void stac(void) { }
-
-static inline unsigned long smap_save(void) { return 0; }
-static inline void smap_restore(unsigned long flags) { }
-
-#define ASM_CLAC
-#define ASM_STAC
-
-#endif /* CONFIG_X86_SMAP */
-
#endif /* __ASSEMBLY__ */

#endif /* _ASM_X86_SMAP_H */
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index c71d1075db93..747df070fb5e 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -382,13 +382,6 @@ static __always_inline void setup_smep(struct cpuinfo_x86 *c)
cr4_set_bits(X86_CR4_SMEP);
}

-static __init int setup_disable_smap(char *arg)
-{
- setup_clear_cpu_cap(X86_FEATURE_SMAP);
- return 1;
-}
-__setup("nosmap", setup_disable_smap);
-
static __always_inline void setup_smap(struct cpuinfo_x86 *c)
{
unsigned long eflags = native_save_fl();
@@ -396,14 +389,8 @@ static __always_inline void setup_smap(struct cpuinfo_x86 *c)
/* This should have been cleared long ago */
BUG_ON(eflags & X86_EFLAGS_AC);

- if (cpu_has(c, X86_FEATURE_SMAP)) {
-#ifdef CONFIG_X86_SMAP
+ if (cpu_has(c, X86_FEATURE_SMAP))
cr4_set_bits(X86_CR4_SMAP);
-#else
- clear_cpu_cap(c, X86_FEATURE_SMAP);
- cr4_clear_bits(X86_CR4_SMAP);
-#endif
- }
}

static __always_inline void setup_umip(struct cpuinfo_x86 *c)
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 9717e6f6fb31..7e7aa1d030a6 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -233,7 +233,7 @@ objtool_args = \
$(if $(CONFIG_FRAME_POINTER),, --no-fp) \
$(if $(CONFIG_GCOV_KERNEL)$(CONFIG_LTO_CLANG), --no-unreachable)\
$(if $(CONFIG_RETPOLINE), --retpoline) \
- $(if $(CONFIG_X86_SMAP), --uaccess) \
+ --uaccess \
$(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \
$(if $(CONFIG_SLS), --sls)

diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 20f44504a644..3a2fffdf49d4 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -146,9 +146,9 @@ objtool_link()
if is_enabled CONFIG_RETPOLINE; then
objtoolopt="${objtoolopt} --retpoline"
fi
- if is_enabled CONFIG_X86_SMAP; then
- objtoolopt="${objtoolopt} --uaccess"
- fi
+
+ objtoolopt="${objtoolopt} --uaccess"
+
if is_enabled CONFIG_SLS; then
objtoolopt="${objtoolopt} --sls"
fi
diff --git a/tools/arch/x86/include/asm/disabled-features.h b/tools/arch/x86/include/asm/disabled-features.h
index 1231d63f836d..1ae0fab7d902 100644
--- a/tools/arch/x86/include/asm/disabled-features.h
+++ b/tools/arch/x86/include/asm/disabled-features.h
@@ -10,12 +10,6 @@
* cpu_feature_enabled().
*/

-#ifdef CONFIG_X86_SMAP
-# define DISABLE_SMAP 0
-#else
-# define DISABLE_SMAP (1<<(X86_FEATURE_SMAP & 31))
-#endif
-
#ifdef CONFIG_X86_UMIP
# define DISABLE_UMIP 0
#else
@@ -80,7 +74,7 @@
#define DISABLED_MASK6 0
#define DISABLED_MASK7 (DISABLE_PTI)
#define DISABLED_MASK8 0
-#define DISABLED_MASK9 (DISABLE_SMAP|DISABLE_SGX)
+#define DISABLED_MASK9 (DISABLE_SGX)
#define DISABLED_MASK10 0
#define DISABLED_MASK11 0
#define DISABLED_MASK12 0

Subject: [tip: objtool/core] libsubcmd: Fix OPTION_GROUP sorting

The following commit has been merged into the objtool/core branch of tip:

Commit-ID: aa3d60e050112ef1373d7216eabe0ee966615527
Gitweb: https://git.kernel.org/tip/aa3d60e050112ef1373d7216eabe0ee966615527
Author: Josh Poimboeuf <[email protected]>
AuthorDate: Mon, 18 Apr 2022 09:50:21 -07:00
Committer: Peter Zijlstra <[email protected]>
CommitterDate: Fri, 22 Apr 2022 12:32:01 +02:00

libsubcmd: Fix OPTION_GROUP sorting

The OPTION_GROUP option type is a way of grouping certain options
together in the printed usage text. It happens to be completely broken,
thanks to the fact that the subcmd option sorting just sorts everything,
without regard for grouping. Luckily, nobody uses this option anyway,
though that will change shortly.

Fix it by sorting each group individually.

Signed-off-by: Josh Poimboeuf <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
Reviewed-by: Miroslav Benes <[email protected]>
Link: https://lkml.kernel.org/r/e167ea3a11e2a9800eb062c1fd0f13e9cd05140c.1650300597.git.jpoimboe@redhat.com
---
tools/lib/subcmd/parse-options.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/tools/lib/subcmd/parse-options.c b/tools/lib/subcmd/parse-options.c
index 39ebf61..9fa7594 100644
--- a/tools/lib/subcmd/parse-options.c
+++ b/tools/lib/subcmd/parse-options.c
@@ -806,9 +806,9 @@ static int option__cmp(const void *va, const void *vb)

static struct option *options__order(const struct option *opts)
{
- int nr_opts = 0, len;
+ int nr_opts = 0, nr_group = 0, len;
const struct option *o = opts;
- struct option *ordered;
+ struct option *opt, *ordered, *group;

for (o = opts; o->type != OPTION_END; o++)
++nr_opts;
@@ -819,7 +819,18 @@ static struct option *options__order(const struct option *opts)
goto out;
memcpy(ordered, opts, len);

- qsort(ordered, nr_opts, sizeof(*o), option__cmp);
+ /* sort each option group individually */
+ for (opt = group = ordered; opt->type != OPTION_END; opt++) {
+ if (opt->type == OPTION_GROUP) {
+ qsort(group, nr_group, sizeof(*opt), option__cmp);
+ group = opt + 1;
+ nr_group = 0;
+ continue;
+ }
+ nr_group++;
+ }
+ qsort(group, nr_group, sizeof(*opt), option__cmp);
+
out:
return ordered;
}

Subject: [tip: objtool/core] objtool: Rename "VMLINUX_VALIDATION" -> "NOINSTR_VALIDATION"

The following commit has been merged into the objtool/core branch of tip:

Commit-ID: 0f620cefd7753175b6258fed85f76c2014ec3799
Gitweb: https://git.kernel.org/tip/0f620cefd7753175b6258fed85f76c2014ec3799
Author: Josh Poimboeuf <[email protected]>
AuthorDate: Mon, 18 Apr 2022 09:50:41 -07:00
Committer: Peter Zijlstra <[email protected]>
CommitterDate: Fri, 22 Apr 2022 12:32:04 +02:00

objtool: Rename "VMLINUX_VALIDATION" -> "NOINSTR_VALIDATION"

CONFIG_VMLINUX_VALIDATION is just the validation of the "noinstr" rules.
That name is a misnomer, because now objtool actually does vmlinux
validation for other reasons.

Rename CONFIG_VMLINUX_VALIDATION to CONFIG_NOINSTR_VALIDATION.

Signed-off-by: Josh Poimboeuf <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
Reviewed-by: Miroslav Benes <[email protected]>
Link: https://lkml.kernel.org/r/173f07e2d6d1afc0874aed975a61783207c6a531.1650300597.git.jpoimboe@redhat.com
---
include/linux/instrumentation.h | 6 +++---
lib/Kconfig.debug | 2 +-
scripts/link-vmlinux.sh | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/include/linux/instrumentation.h b/include/linux/instrumentation.h
index 9111a37..bc7babe 100644
--- a/include/linux/instrumentation.h
+++ b/include/linux/instrumentation.h
@@ -2,7 +2,7 @@
#ifndef __LINUX_INSTRUMENTATION_H
#define __LINUX_INSTRUMENTATION_H

-#ifdef CONFIG_VMLINUX_VALIDATION
+#ifdef CONFIG_NOINSTR_VALIDATION

#include <linux/stringify.h>

@@ -53,9 +53,9 @@
".popsection\n\t" : : "i" (c)); \
})
#define instrumentation_end() __instrumentation_end(__COUNTER__)
-#else /* !CONFIG_VMLINUX_VALIDATION */
+#else /* !CONFIG_NOINSTR_VALIDATION */
# define instrumentation_begin() do { } while(0)
# define instrumentation_end() do { } while(0)
-#endif /* CONFIG_VMLINUX_VALIDATION */
+#endif /* CONFIG_NOINSTR_VALIDATION */

#endif /* __LINUX_INSTRUMENTATION_H */
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 7d2bbc3..73359d6 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -500,7 +500,7 @@ config STACK_VALIDATION
For more information, see
tools/objtool/Documentation/stack-validation.txt.

-config VMLINUX_VALIDATION
+config NOINSTR_VALIDATION
bool
depends on HAVE_OBJTOOL && DEBUG_ENTRY
select OBJTOOL
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 90c9c4c..fce4f41 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -160,7 +160,7 @@ objtool_link()
objtoolopt="${objtoolopt} --lto"
fi

- if is_enabled CONFIG_VMLINUX_VALIDATION; then
+ if is_enabled CONFIG_NOINSTR_VALIDATION; then
objtoolopt="${objtoolopt} --noinstr"
fi

Subject: [tip: objtool/core] objtool: Ditch subcommands

The following commit has been merged into the objtool/core branch of tip:

Commit-ID: b51277eb9775ce916f9efd2c51533e481180c1e8
Gitweb: https://git.kernel.org/tip/b51277eb9775ce916f9efd2c51533e481180c1e8
Author: Josh Poimboeuf <[email protected]>
AuthorDate: Mon, 18 Apr 2022 09:50:27 -07:00
Committer: Peter Zijlstra <[email protected]>
CommitterDate: Fri, 22 Apr 2022 12:32:01 +02:00

objtool: Ditch subcommands

Objtool has a fairly singular focus. It runs on object files and does
validations and transformations which can be combined in various ways.
The subcommand model has never been a good fit, making it awkward to
combine and remove options.

Remove the "check" and "orc" subcommands in favor of a more traditional
cmdline option model. This makes it much more flexible to use, and
easier to port individual features to other arches.

Signed-off-by: Josh Poimboeuf <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
Reviewed-by: Miroslav Benes <[email protected]>
Link: https://lkml.kernel.org/r/5c61ebf805e90aefc5fa62bc63468ffae53b9df6.1650300597.git.jpoimboe@redhat.com
---
scripts/Makefile.build | 2 +-
scripts/link-vmlinux.sh | 13 +--
tools/objtool/Build | 12 +--
tools/objtool/Makefile | 8 +--
tools/objtool/builtin-check.c | 56 +++++++++++---
tools/objtool/builtin-orc.c | 73 +------------------
tools/objtool/check.c | 8 ++-
tools/objtool/include/objtool/builtin.h | 5 +-
tools/objtool/objtool.c | 97 +------------------------
tools/objtool/weak.c | 9 +--
10 files changed, 72 insertions(+), 211 deletions(-)
delete mode 100644 tools/objtool/builtin-orc.c

diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index dd9d582..116c727 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -227,9 +227,9 @@ ifdef CONFIG_STACK_VALIDATION
objtool := $(objtree)/tools/objtool/objtool

objtool_args = \
- $(if $(CONFIG_UNWINDER_ORC),orc generate,check) \
$(if $(CONFIG_X86_KERNEL_IBT), --lto --ibt) \
$(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \
+ $(if $(CONFIG_UNWINDER_ORC), --orc) \
$(if $(CONFIG_RETPOLINE), --retpoline) \
$(if $(CONFIG_SLS), --sls) \
$(if $(CONFIG_X86_SMAP), --uaccess) \
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index c6e9fef..f6db79b 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -113,9 +113,6 @@ objtool_link()

# Don't perform vmlinux validation unless explicitly requested,
# but run objtool on vmlinux.o now that we have an object file.
- if is_enabled CONFIG_UNWINDER_ORC; then
- objtoolcmd="orc generate"
- fi

if is_enabled CONFIG_X86_KERNEL_IBT; then
objtoolopt="${objtoolopt} --ibt"
@@ -125,6 +122,10 @@ objtool_link()
objtoolopt="${objtoolopt} --mcount"
fi

+ if is_enabled CONFIG_UNWINDER_ORC; then
+ objtoolopt="${objtoolopt} --orc"
+ fi
+
objtoolopt="${objtoolopt} --lto"
fi

@@ -134,10 +135,6 @@ objtool_link()

if [ -n "${objtoolopt}" ]; then

- if [ -z "${objtoolcmd}" ]; then
- objtoolcmd="check"
- fi
-
if is_enabled CONFIG_RETPOLINE; then
objtoolopt="${objtoolopt} --retpoline"
fi
@@ -161,7 +158,7 @@ objtool_link()
objtoolopt="${objtoolopt} --vmlinux"

info OBJTOOL ${1}
- tools/objtool/objtool ${objtoolcmd} ${objtoolopt} ${1}
+ tools/objtool/objtool ${objtoolopt} ${1}
fi
}

diff --git a/tools/objtool/Build b/tools/objtool/Build
index b7222d5..33f2ee5 100644
--- a/tools/objtool/Build
+++ b/tools/objtool/Build
@@ -2,17 +2,15 @@ objtool-y += arch/$(SRCARCH)/

objtool-y += weak.o

-objtool-$(SUBCMD_CHECK) += check.o
-objtool-$(SUBCMD_CHECK) += special.o
-objtool-$(SUBCMD_ORC) += check.o
-objtool-$(SUBCMD_ORC) += orc_gen.o
-objtool-$(SUBCMD_ORC) += orc_dump.o
-
+objtool-y += check.o
+objtool-y += special.o
objtool-y += builtin-check.o
-objtool-y += builtin-orc.o
objtool-y += elf.o
objtool-y += objtool.o

+objtool-$(BUILD_ORC) += orc_gen.o
+objtool-$(BUILD_ORC) += orc_dump.o
+
objtool-y += libstring.o
objtool-y += libctype.o
objtool-y += str_error_r.o
diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile
index 0dbd397..061cf1c 100644
--- a/tools/objtool/Makefile
+++ b/tools/objtool/Makefile
@@ -39,15 +39,13 @@ CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED)

AWK = awk

-SUBCMD_CHECK := n
-SUBCMD_ORC := n
+BUILD_ORC := n

ifeq ($(SRCARCH),x86)
- SUBCMD_CHECK := y
- SUBCMD_ORC := y
+ BUILD_ORC := y
endif

-export SUBCMD_CHECK SUBCMD_ORC
+export BUILD_ORC
export srctree OUTPUT CFLAGS SRCARCH AWK
include $(srctree)/tools/build/Makefile.include

diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index bc447b3..8c3eed5 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -3,16 +3,6 @@
* Copyright (C) 2015-2017 Josh Poimboeuf <[email protected]>
*/

-/*
- * objtool check:
- *
- * This command analyzes every .o file and ensures the validity of its stack
- * trace metadata. It enforces a set of rules on asm code and C inline
- * assembly code so that stack traces can be reliable.
- *
- * For more information, see tools/objtool/Documentation/stack-validation.txt.
- */
-
#include <subcmd/parse-options.h>
#include <string.h>
#include <stdlib.h>
@@ -22,7 +12,7 @@
struct opts opts;

static const char * const check_usage[] = {
- "objtool check <actions> [<options>] file.o",
+ "objtool <actions> [<options>] file.o",
NULL,
};

@@ -31,14 +21,26 @@ static const char * const env_usage[] = {
NULL,
};

+static int parse_dump(const struct option *opt, const char *str, int unset)
+{
+ if (!str || !strcmp(str, "orc")) {
+ opts.dump_orc = true;
+ return 0;
+ }
+
+ return -1;
+}
+
const struct option check_options[] = {
OPT_GROUP("Actions:"),
OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"),
OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls for ftrace"),
OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"),
+ OPT_BOOLEAN('o', "orc", &opts.orc, "generate ORC metadata"),
OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate retpoline usage"),
OPT_BOOLEAN('l', "sls", &opts.sls, "validate straight-line-speculation mitigations"),
OPT_BOOLEAN('u', "uaccess", &opts.uaccess, "validate uaccess rules for SMAP"),
+ OPT_CALLBACK_OPTARG(0, "dump", NULL, NULL, "orc", "dump metadata", parse_dump),

OPT_GROUP("Options:"),
OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"),
@@ -81,7 +83,31 @@ int cmd_parse_options(int argc, const char **argv, const char * const usage[])
return argc;
}

-int cmd_check(int argc, const char **argv)
+static bool opts_valid(void)
+{
+ if (opts.ibt ||
+ opts.mcount ||
+ opts.noinstr ||
+ opts.orc ||
+ opts.retpoline ||
+ opts.sls ||
+ opts.uaccess) {
+ if (opts.dump_orc) {
+ fprintf(stderr, "--dump can't be combined with other options\n");
+ return false;
+ }
+
+ return true;
+ }
+
+ if (opts.dump_orc)
+ return true;
+
+ fprintf(stderr, "At least one command required\n");
+ return false;
+}
+
+int objtool_run(int argc, const char **argv)
{
const char *objname;
struct objtool_file *file;
@@ -90,6 +116,12 @@ int cmd_check(int argc, const char **argv)
argc = cmd_parse_options(argc, argv, check_usage);
objname = argv[0];

+ if (!opts_valid())
+ return 1;
+
+ if (opts.dump_orc)
+ return orc_dump(objname);
+
file = objtool_open_read(objname);
if (!file)
return 1;
diff --git a/tools/objtool/builtin-orc.c b/tools/objtool/builtin-orc.c
deleted file mode 100644
index 17f8b93..0000000
--- a/tools/objtool/builtin-orc.c
+++ /dev/null
@@ -1,73 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2017 Josh Poimboeuf <[email protected]>
- */
-
-/*
- * objtool orc:
- *
- * This command analyzes a .o file and adds .orc_unwind and .orc_unwind_ip
- * sections to it, which is used by the in-kernel ORC unwinder.
- *
- * This command is a superset of "objtool check".
- */
-
-#include <string.h>
-#include <objtool/builtin.h>
-#include <objtool/objtool.h>
-
-static const char *orc_usage[] = {
- "objtool orc generate [<options>] file.o",
- "objtool orc dump file.o",
- NULL,
-};
-
-int cmd_orc(int argc, const char **argv)
-{
- const char *objname;
-
- argc--; argv++;
- if (argc <= 0)
- usage_with_options(orc_usage, check_options);
-
- if (!strncmp(argv[0], "gen", 3)) {
- struct objtool_file *file;
- int ret;
-
- argc = cmd_parse_options(argc, argv, orc_usage);
- objname = argv[0];
-
- file = objtool_open_read(objname);
- if (!file)
- return 1;
-
- ret = check(file);
- if (ret)
- return ret;
-
- if (list_empty(&file->insn_list))
- return 0;
-
- ret = orc_create(file);
- if (ret)
- return ret;
-
- if (!file->elf->changed)
- return 0;
-
- return elf_write(file->elf);
- }
-
- if (!strcmp(argv[0], "dump")) {
- if (argc != 2)
- usage_with_options(orc_usage, check_options);
-
- objname = argv[1];
-
- return orc_dump(objname);
- }
-
- usage_with_options(orc_usage, check_options);
-
- return 0;
-}
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 3362cc3..16a6c4b 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -3949,6 +3949,14 @@ int check(struct objtool_file *file)
warnings += ret;
}

+ if (opts.orc && !list_empty(&file->insn_list)) {
+ ret = orc_create(file);
+ if (ret < 0)
+ goto out;
+ warnings += ret;
+ }
+
+
if (opts.stats) {
printf("nr_insns_visited: %ld\n", nr_insns_visited);
printf("nr_cfi: %ld\n", nr_cfi);
diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h
index 87c1a73..44548e2 100644
--- a/tools/objtool/include/objtool/builtin.h
+++ b/tools/objtool/include/objtool/builtin.h
@@ -11,9 +11,11 @@ extern const struct option check_options[];

struct opts {
/* actions: */
+ bool dump_orc;
bool ibt;
bool mcount;
bool noinstr;
+ bool orc;
bool retpoline;
bool sls;
bool uaccess;
@@ -34,7 +36,6 @@ extern struct opts opts;

extern int cmd_parse_options(int argc, const char **argv, const char * const usage[]);

-extern int cmd_check(int argc, const char **argv);
-extern int cmd_orc(int argc, const char **argv);
+extern int objtool_run(int argc, const char **argv);

#endif /* _BUILTIN_H */
diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c
index a0f3d3c..512669c 100644
--- a/tools/objtool/objtool.c
+++ b/tools/objtool/objtool.c
@@ -3,16 +3,6 @@
* Copyright (C) 2015 Josh Poimboeuf <[email protected]>
*/

-/*
- * objtool:
- *
- * The 'check' subcmd analyzes every .o file and ensures the validity of its
- * stack trace metadata. It enforces a set of rules on asm code and C inline
- * assembly code so that stack traces can be reliable.
- *
- * For more information, see tools/objtool/Documentation/stack-validation.txt.
- */
-
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
@@ -26,20 +16,6 @@
#include <objtool/objtool.h>
#include <objtool/warn.h>

-struct cmd_struct {
- const char *name;
- int (*fn)(int, const char **);
- const char *help;
-};
-
-static const char objtool_usage_string[] =
- "objtool COMMAND [ARGS]";
-
-static struct cmd_struct objtool_cmds[] = {
- {"check", cmd_check, "Perform stack metadata validation on an object file" },
- {"orc", cmd_orc, "Generate in-place ORC unwind tables for an object file" },
-};
-
bool help;

const char *objname;
@@ -161,70 +137,6 @@ void objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func)
f->pv_ops[idx].clean = false;
}

-static void cmd_usage(void)
-{
- unsigned int i, longest = 0;
-
- printf("\n usage: %s\n\n", objtool_usage_string);
-
- for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) {
- if (longest < strlen(objtool_cmds[i].name))
- longest = strlen(objtool_cmds[i].name);
- }
-
- puts(" Commands:");
- for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) {
- printf(" %-*s ", longest, objtool_cmds[i].name);
- puts(objtool_cmds[i].help);
- }
-
- printf("\n");
-
- if (!help)
- exit(129);
- exit(0);
-}
-
-static void handle_options(int *argc, const char ***argv)
-{
- while (*argc > 0) {
- const char *cmd = (*argv)[0];
-
- if (cmd[0] != '-')
- break;
-
- if (!strcmp(cmd, "--help") || !strcmp(cmd, "-h")) {
- help = true;
- break;
- } else {
- fprintf(stderr, "Unknown option: %s\n", cmd);
- cmd_usage();
- }
-
- (*argv)++;
- (*argc)--;
- }
-}
-
-static void handle_internal_command(int argc, const char **argv)
-{
- const char *cmd = argv[0];
- unsigned int i, ret;
-
- for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) {
- struct cmd_struct *p = objtool_cmds+i;
-
- if (strcmp(p->name, cmd))
- continue;
-
- ret = p->fn(argc, argv);
-
- exit(ret);
- }
-
- cmd_usage();
-}
-
int main(int argc, const char **argv)
{
static const char *UNUSED = "OBJTOOL_NOT_IMPLEMENTED";
@@ -233,14 +145,7 @@ int main(int argc, const char **argv)
exec_cmd_init("objtool", UNUSED, UNUSED, UNUSED);
pager_init(UNUSED);

- argv++;
- argc--;
- handle_options(&argc, &argv);
-
- if (!argc || help)
- cmd_usage();
-
- handle_internal_command(argc, argv);
+ objtool_run(argc, argv);

return 0;
}
diff --git a/tools/objtool/weak.c b/tools/objtool/weak.c
index 8314e82..d83f607 100644
--- a/tools/objtool/weak.c
+++ b/tools/objtool/weak.c
@@ -15,17 +15,12 @@
return ENOSYS; \
})

-int __weak check(struct objtool_file *file)
-{
- UNSUPPORTED("check subcommand");
-}
-
int __weak orc_dump(const char *_objname)
{
- UNSUPPORTED("orc");
+ UNSUPPORTED("ORC");
}

int __weak orc_create(struct objtool_file *file)
{
- UNSUPPORTED("orc");
+ UNSUPPORTED("ORC");
}

2022-04-22 21:05:52

by Miroslav Benes

[permalink] [raw]
Subject: Re: [PATCH v2 24/25] objtool: Remove --lto and --vmlinux in favor of --link

> -static void init_insn_state(struct insn_state *state, struct section *sec)
> +static void init_insn_state(struct objtool_file *file, struct insn_state *state,
> + struct section *sec)

file is not needed anymore here.

Miroslav

Subject: [tip: objtool/core] objtool: Add CONFIG_OBJTOOL

The following commit has been merged into the objtool/core branch of tip:

Commit-ID: 03f16cd020eb8bb2eb837e2090086f296a9fa91d
Gitweb: https://git.kernel.org/tip/03f16cd020eb8bb2eb837e2090086f296a9fa91d
Author: Josh Poimboeuf <[email protected]>
AuthorDate: Mon, 18 Apr 2022 09:50:36 -07:00
Committer: Peter Zijlstra <[email protected]>
CommitterDate: Fri, 22 Apr 2022 12:32:03 +02:00

objtool: Add CONFIG_OBJTOOL

Now that stack validation is an optional feature of objtool, add
CONFIG_OBJTOOL and replace most usages of CONFIG_STACK_VALIDATION with
it.

CONFIG_STACK_VALIDATION can now be considered to be frame-pointer
specific. CONFIG_UNWINDER_ORC is already inherently valid for live
patching, so no need to "validate" it.

Signed-off-by: Josh Poimboeuf <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
Reviewed-by: Miroslav Benes <[email protected]>
Link: https://lkml.kernel.org/r/939bf3d85604b2a126412bf11af6e3bd3b872bcb.1650300597.git.jpoimboe@redhat.com
---
Makefile | 2 +-
arch/Kconfig | 8 ++++++--
arch/x86/Kconfig | 18 ++++++++++-------
arch/x86/Kconfig.debug | 2 +-
arch/x86/include/asm/jump_label.h | 6 +++---
arch/x86/kernel/alternative.c | 6 +++---
include/linux/compiler.h | 6 +++---
include/linux/instrumentation.h | 6 +++---
include/linux/objtool.h | 6 +++---
kernel/trace/Kconfig | 1 +-
lib/Kconfig.debug | 20 ++++++++++---------
lib/Kconfig.kcsan | 3 ++-
lib/Kconfig.ubsan | 2 +-
scripts/Makefile.build | 4 ++--
scripts/link-vmlinux.sh | 32 ++++++++++++++++--------------
scripts/package/builddeb | 2 +-
tools/include/linux/objtool.h | 6 +++---
17 files changed, 73 insertions(+), 57 deletions(-)

diff --git a/Makefile b/Makefile
index fa5112a..2507076 100644
--- a/Makefile
+++ b/Makefile
@@ -1302,7 +1302,7 @@ install: sub_make_done :=
# ---------------------------------------------------------------------------
# Tools

-ifdef CONFIG_STACK_VALIDATION
+ifdef CONFIG_OBJTOOL
prepare: tools/objtool
endif

diff --git a/arch/Kconfig b/arch/Kconfig
index 29b0167..04cdef1 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -1028,11 +1028,14 @@ config ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
depends on MMU
select ARCH_HAS_ELF_RANDOMIZE

+config HAVE_OBJTOOL
+ bool
+
config HAVE_STACK_VALIDATION
bool
help
- Architecture supports the 'objtool check' host tool command, which
- performs compile-time stack metadata validation.
+ Architecture supports objtool compile-time frame pointer rule
+ validation.

config HAVE_RELIABLE_STACKTRACE
bool
@@ -1302,6 +1305,7 @@ config HAVE_STATIC_CALL
config HAVE_STATIC_CALL_INLINE
bool
depends on HAVE_STATIC_CALL
+ select OBJTOOL

config HAVE_PREEMPT_DYNAMIC
bool
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 4bed3ab..43e26ee 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -188,7 +188,7 @@ config X86
select HAVE_CONTEXT_TRACKING if X86_64
select HAVE_CONTEXT_TRACKING_OFFSTACK if HAVE_CONTEXT_TRACKING
select HAVE_C_RECORDMCOUNT
- select HAVE_OBJTOOL_MCOUNT if STACK_VALIDATION
+ select HAVE_OBJTOOL_MCOUNT if HAVE_OBJTOOL
select HAVE_BUILDTIME_MCOUNT_SORT
select HAVE_DEBUG_KMEMLEAK
select HAVE_DMA_CONTIGUOUS
@@ -231,6 +231,7 @@ config X86
select HAVE_MOVE_PMD
select HAVE_MOVE_PUD
select HAVE_NMI
+ select HAVE_OBJTOOL if X86_64
select HAVE_OPTPROBES
select HAVE_PCSPKR_PLATFORM
select HAVE_PERF_EVENTS
@@ -239,17 +240,17 @@ config X86
select HAVE_PCI
select HAVE_PERF_REGS
select HAVE_PERF_USER_STACK_DUMP
- select MMU_GATHER_RCU_TABLE_FREE if PARAVIRT
+ select MMU_GATHER_RCU_TABLE_FREE if PARAVIRT
select HAVE_POSIX_CPU_TIMERS_TASK_WORK
select HAVE_REGS_AND_STACK_ACCESS_API
- select HAVE_RELIABLE_STACKTRACE if X86_64 && (UNWINDER_FRAME_POINTER || UNWINDER_ORC) && STACK_VALIDATION
+ select HAVE_RELIABLE_STACKTRACE if UNWINDER_ORC || STACK_VALIDATION
select HAVE_FUNCTION_ARG_ACCESS_API
select HAVE_SETUP_PER_CPU_AREA
select HAVE_SOFTIRQ_ON_OWN_STACK
select HAVE_STACKPROTECTOR if CC_HAS_SANE_STACKPROTECTOR
- select HAVE_STACK_VALIDATION if X86_64
+ select HAVE_STACK_VALIDATION if HAVE_OBJTOOL
select HAVE_STATIC_CALL
- select HAVE_STATIC_CALL_INLINE if HAVE_STACK_VALIDATION
+ select HAVE_STATIC_CALL_INLINE if HAVE_OBJTOOL
select HAVE_PREEMPT_DYNAMIC_CALL
select HAVE_RSEQ
select HAVE_SYSCALL_TRACEPOINTS
@@ -268,7 +269,6 @@ config X86
select RTC_MC146818_LIB
select SPARSE_IRQ
select SRCU
- select STACK_VALIDATION if HAVE_STACK_VALIDATION && (HAVE_STATIC_CALL_INLINE || RETPOLINE)
select SYSCTL_EXCEPTION_TRACE
select THREAD_INFO_IN_TASK
select TRACE_IRQFLAGS_SUPPORT
@@ -459,6 +459,7 @@ config GOLDFISH

config RETPOLINE
bool "Avoid speculative indirect branches in kernel"
+ select OBJTOOL if HAVE_OBJTOOL
default y
help
Compile kernel with the retpoline compiler options to guard against
@@ -472,6 +473,7 @@ config CC_HAS_SLS
config SLS
bool "Mitigate Straight-Line-Speculation"
depends on CC_HAS_SLS && X86_64
+ select OBJTOOL if HAVE_OBJTOOL
default n
help
Compile the kernel with straight-line-speculation options to guard
@@ -1819,6 +1821,7 @@ config ARCH_RANDOM
config X86_SMAP
def_bool y
prompt "Supervisor Mode Access Prevention" if EXPERT
+ select OBJTOOL if HAVE_OBJTOOL
help
Supervisor Mode Access Prevention (SMAP) is a security
feature in newer Intel processors. There is a small
@@ -1855,9 +1858,10 @@ config CC_HAS_IBT
config X86_KERNEL_IBT
prompt "Indirect Branch Tracking"
bool
- depends on X86_64 && CC_HAS_IBT && STACK_VALIDATION
+ depends on X86_64 && CC_HAS_IBT && HAVE_OBJTOOL
# https://github.com/llvm/llvm-project/commit/9d7001eba9c4cb311e03cd8cdc231f9e579f2d0f
depends on !LD_IS_LLD || LLD_VERSION >= 140000
+ select OBJTOOL
help
Build the kernel with support for Indirect Branch Tracking, a
hardware support course-grain forward-edge Control Flow Integrity
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index d3a6f74..d872a75 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -237,7 +237,7 @@ choice
config UNWINDER_ORC
bool "ORC unwinder"
depends on X86_64
- select STACK_VALIDATION
+ select OBJTOOL
help
This option enables the ORC (Oops Rewind Capability) unwinder for
unwinding kernel stack traces. It uses a custom data format which is
diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h
index 0449b12..3ce0e67 100644
--- a/arch/x86/include/asm/jump_label.h
+++ b/arch/x86/include/asm/jump_label.h
@@ -20,7 +20,7 @@
_ASM_PTR "%c0 + %c1 - .\n\t" \
".popsection \n\t"

-#ifdef CONFIG_STACK_VALIDATION
+#ifdef CONFIG_OBJTOOL

static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
{
@@ -34,7 +34,7 @@ l_yes:
return true;
}

-#else
+#else /* !CONFIG_OBJTOOL */

static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch)
{
@@ -48,7 +48,7 @@ l_yes:
return true;
}

-#endif /* STACK_VALIDATION */
+#endif /* CONFIG_OBJTOOL */

static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch)
{
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index d374cb3..3c66073 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -338,7 +338,7 @@ next:
}
}

-#if defined(CONFIG_RETPOLINE) && defined(CONFIG_STACK_VALIDATION)
+#if defined(CONFIG_RETPOLINE) && defined(CONFIG_OBJTOOL)

/*
* CALL/JMP *%\reg
@@ -507,11 +507,11 @@ void __init_or_module noinline apply_retpolines(s32 *start, s32 *end)
}
}

-#else /* !RETPOLINES || !CONFIG_STACK_VALIDATION */
+#else /* !CONFIG_RETPOLINE || !CONFIG_OBJTOOL */

void __init_or_module noinline apply_retpolines(s32 *start, s32 *end) { }

-#endif /* CONFIG_RETPOLINE && CONFIG_STACK_VALIDATION */
+#endif /* CONFIG_RETPOLINE && CONFIG_OBJTOOL */

#ifdef CONFIG_X86_KERNEL_IBT

diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 219aa5d..01ce94b 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -109,7 +109,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
#endif

/* Unreachable code */
-#ifdef CONFIG_STACK_VALIDATION
+#ifdef CONFIG_OBJTOOL
/*
* These macros help objtool understand GCC code flow for unreachable code.
* The __COUNTER__ based labels are a hack to make each instance of the macros
@@ -128,10 +128,10 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
/* Annotate a C jump table to allow objtool to follow the code flow */
#define __annotate_jump_table __section(".rodata..c_jump_table")

-#else
+#else /* !CONFIG_OBJTOOL */
#define annotate_unreachable()
#define __annotate_jump_table
-#endif
+#endif /* CONFIG_OBJTOOL */

#ifndef unreachable
# define unreachable() do { \
diff --git a/include/linux/instrumentation.h b/include/linux/instrumentation.h
index 24359b4..9111a37 100644
--- a/include/linux/instrumentation.h
+++ b/include/linux/instrumentation.h
@@ -2,7 +2,7 @@
#ifndef __LINUX_INSTRUMENTATION_H
#define __LINUX_INSTRUMENTATION_H

-#if defined(CONFIG_DEBUG_ENTRY) && defined(CONFIG_STACK_VALIDATION)
+#ifdef CONFIG_VMLINUX_VALIDATION

#include <linux/stringify.h>

@@ -53,9 +53,9 @@
".popsection\n\t" : : "i" (c)); \
})
#define instrumentation_end() __instrumentation_end(__COUNTER__)
-#else
+#else /* !CONFIG_VMLINUX_VALIDATION */
# define instrumentation_begin() do { } while(0)
# define instrumentation_end() do { } while(0)
-#endif
+#endif /* CONFIG_VMLINUX_VALIDATION */

#endif /* __LINUX_INSTRUMENTATION_H */
diff --git a/include/linux/objtool.h b/include/linux/objtool.h
index 586d357..977d90b 100644
--- a/include/linux/objtool.h
+++ b/include/linux/objtool.h
@@ -38,7 +38,7 @@ struct unwind_hint {
#define UNWIND_HINT_TYPE_REGS_PARTIAL 2
#define UNWIND_HINT_TYPE_FUNC 3

-#ifdef CONFIG_STACK_VALIDATION
+#ifdef CONFIG_OBJTOOL

#ifndef __ASSEMBLY__

@@ -157,7 +157,7 @@ struct unwind_hint {

#endif /* __ASSEMBLY__ */

-#else /* !CONFIG_STACK_VALIDATION */
+#else /* !CONFIG_OBJTOOL */

#ifndef __ASSEMBLY__

@@ -179,6 +179,6 @@ struct unwind_hint {
.endm
#endif

-#endif /* CONFIG_STACK_VALIDATION */
+#endif /* CONFIG_OBJTOOL */

#endif /* _LINUX_OBJTOOL_H */
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 2c43e32..2956bc2 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -728,6 +728,7 @@ config FTRACE_MCOUNT_USE_OBJTOOL
depends on !FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY
depends on !FTRACE_MCOUNT_USE_CC
depends on FTRACE_MCOUNT_RECORD
+ select OBJTOOL

config FTRACE_MCOUNT_USE_RECORDMCOUNT
def_bool y
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 075cd25..c0e4e47 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -485,24 +485,25 @@ config FRAME_POINTER
larger and slower, but it gives very useful debugging information
in case of kernel bugs. (precise oopses/stacktraces/warnings)

+config OBJTOOL
+ bool
+
config STACK_VALIDATION
bool "Compile-time stack metadata validation"
- depends on HAVE_STACK_VALIDATION
+ depends on HAVE_STACK_VALIDATION && UNWINDER_FRAME_POINTER
+ select OBJTOOL
default n
help
- Add compile-time checks to validate stack metadata, including frame
- pointers (if CONFIG_FRAME_POINTER is enabled). This helps ensure
- that runtime stack traces are more reliable.
-
- This is also a prerequisite for generation of ORC unwind data, which
- is needed for CONFIG_UNWINDER_ORC.
+ Validate frame pointer rules at compile-time. This helps ensure that
+ runtime stack traces are more reliable.

For more information, see
tools/objtool/Documentation/stack-validation.txt.

config VMLINUX_VALIDATION
bool
- depends on STACK_VALIDATION && DEBUG_ENTRY
+ depends on HAVE_OBJTOOL && DEBUG_ENTRY
+ select OBJTOOL
default y

config VMLINUX_MAP
@@ -2035,10 +2036,11 @@ config KCOV
bool "Code coverage for fuzzing"
depends on ARCH_HAS_KCOV
depends on CC_HAS_SANCOV_TRACE_PC || GCC_PLUGINS
- depends on !ARCH_WANTS_NO_INSTR || STACK_VALIDATION || \
+ depends on !ARCH_WANTS_NO_INSTR || HAVE_OBJTOOL || \
GCC_VERSION >= 120000 || CLANG_VERSION >= 130000
select DEBUG_FS
select GCC_PLUGIN_SANCOV if !CC_HAS_SANCOV_TRACE_PC
+ select OBJTOOL if HAVE_OBJTOOL
help
KCOV exposes kernel code coverage information in a form suitable
for coverage-guided fuzzing (randomized testing).
diff --git a/lib/Kconfig.kcsan b/lib/Kconfig.kcsan
index de02244..901c3b5 100644
--- a/lib/Kconfig.kcsan
+++ b/lib/Kconfig.kcsan
@@ -187,7 +187,8 @@ config KCSAN_WEAK_MEMORY
# We can either let objtool nop __tsan_func_{entry,exit}() and builtin
# atomics instrumentation in .noinstr.text, or use a compiler that can
# implement __no_kcsan to really remove all instrumentation.
- depends on STACK_VALIDATION || CC_IS_GCC || CLANG_VERSION >= 140000
+ depends on HAVE_OBJTOOL || CC_IS_GCC || CLANG_VERSION >= 140000
+ select OBJTOOL if HAVE_OBJTOOL
help
Enable support for modeling a subset of weak memory, which allows
detecting a subset of data races due to missing memory barriers.
diff --git a/lib/Kconfig.ubsan b/lib/Kconfig.ubsan
index f3c57ed..c4fe15d 100644
--- a/lib/Kconfig.ubsan
+++ b/lib/Kconfig.ubsan
@@ -94,7 +94,7 @@ config UBSAN_UNREACHABLE
bool "Perform checking for unreachable code"
# objtool already handles unreachable checking and gets angry about
# seeing UBSan instrumentation located in unreachable places.
- depends on !STACK_VALIDATION
+ depends on !(OBJTOOL && (STACK_VALIDATION || UNWINDER_ORC || X86_SMAP))
depends on $(cc-option,-fsanitize=unreachable)
help
This option enables -fsanitize=unreachable which checks for control
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index d5e15ae..0f73e02 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -222,7 +222,7 @@ cmd_record_mcount = $(if $(findstring $(strip $(CC_FLAGS_FTRACE)),$(_c_flags)),
$(sub_cmd_record_mcount))
endif # CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT

-ifdef CONFIG_STACK_VALIDATION
+ifdef CONFIG_OBJTOOL

objtool := $(objtree)/tools/objtool/objtool

@@ -241,7 +241,7 @@ objtool_args = \
cmd_objtool = $(if $(objtool-enabled), ; $(objtool) $(objtool_args) $@)
cmd_gen_objtooldep = $(if $(objtool-enabled), { echo ; echo '$@: $$(wildcard $(objtool))' ; } >> $(dot-target).cmd)

-endif # CONFIG_STACK_VALIDATION
+endif # CONFIG_OBJTOOL

ifneq ($(CONFIG_LTO_CLANG)$(CONFIG_X86_KERNEL_IBT),)

diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 0140bfa..5101a7f 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -108,8 +108,11 @@ objtool_link()
local objtoolcmd;
local objtoolopt;

- if is_enabled CONFIG_STACK_VALIDATION && \
- ( is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT ); then
+ if ! is_enabled CONFIG_OBJTOOL; then
+ return;
+ fi
+
+ if is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT; then

# Don't perform vmlinux validation unless explicitly requested,
# but run objtool on vmlinux.o now that we have an object file.
@@ -126,10 +129,23 @@ objtool_link()
objtoolopt="${objtoolopt} --orc"
fi

+ if is_enabled CONFIG_RETPOLINE; then
+ objtoolopt="${objtoolopt} --retpoline"
+ fi
+
+ if is_enabled CONFIG_SLS; then
+ objtoolopt="${objtoolopt} --sls"
+ fi
+
if is_enabled CONFIG_STACK_VALIDATION; then
objtoolopt="${objtoolopt} --stackval"
fi

+ if is_enabled CONFIG_X86_SMAP; then
+ objtoolopt="${objtoolopt} --uaccess"
+ fi
+
+
objtoolopt="${objtoolopt} --lto"
fi

@@ -139,18 +155,6 @@ objtool_link()

if [ -n "${objtoolopt}" ]; then

- if is_enabled CONFIG_RETPOLINE; then
- objtoolopt="${objtoolopt} --retpoline"
- fi
-
- if is_enabled CONFIG_SLS; then
- objtoolopt="${objtoolopt} --sls"
- fi
-
- if is_enabled CONFIG_X86_SMAP; then
- objtoolopt="${objtoolopt} --uaccess"
- fi
-
if ! is_enabled CONFIG_FRAME_POINTER; then
objtoolopt="${objtoolopt} --no-fp"
fi
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
index 91a502b..67cd420 100755
--- a/scripts/package/builddeb
+++ b/scripts/package/builddeb
@@ -67,7 +67,7 @@ deploy_kernel_headers () {
) > debian/hdrsrcfiles

{
- if is_enabled CONFIG_STACK_VALIDATION; then
+ if is_enabled CONFIG_OBJTOOL; then
echo tools/objtool/objtool
fi

diff --git a/tools/include/linux/objtool.h b/tools/include/linux/objtool.h
index 586d357..977d90b 100644
--- a/tools/include/linux/objtool.h
+++ b/tools/include/linux/objtool.h
@@ -38,7 +38,7 @@ struct unwind_hint {
#define UNWIND_HINT_TYPE_REGS_PARTIAL 2
#define UNWIND_HINT_TYPE_FUNC 3

-#ifdef CONFIG_STACK_VALIDATION
+#ifdef CONFIG_OBJTOOL

#ifndef __ASSEMBLY__

@@ -157,7 +157,7 @@ struct unwind_hint {

#endif /* __ASSEMBLY__ */

-#else /* !CONFIG_STACK_VALIDATION */
+#else /* !CONFIG_OBJTOOL */

#ifndef __ASSEMBLY__

@@ -179,6 +179,6 @@ struct unwind_hint {
.endm
#endif

-#endif /* CONFIG_STACK_VALIDATION */
+#endif /* CONFIG_OBJTOOL */

#endif /* _LINUX_OBJTOOL_H */

2022-04-22 22:34:58

by Josh Poimboeuf

[permalink] [raw]
Subject: [PATCH v2 19/25] objtool: Make static call annotation optional

As part of making objtool more modular, put the existing static call
code behind a new '--static-call' option.

Signed-off-by: Josh Poimboeuf <[email protected]>
---
scripts/Makefile.build | 1 +
scripts/link-vmlinux.sh | 5 ++++-
tools/objtool/builtin-check.c | 2 ++
tools/objtool/check.c | 10 ++++++----
tools/objtool/include/objtool/builtin.h | 1 +
5 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 6eb99cb08821..3f20d565733c 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -233,6 +233,7 @@ objtool_args = \
$(if $(CONFIG_RETPOLINE), --retpoline) \
$(if $(CONFIG_SLS), --sls) \
$(if $(CONFIG_STACK_VALIDATION), --stackval) \
+ $(if $(CONFIG_HAVE_STATIC_CALL_INLINE), --static-call) \
$(if $(CONFIG_X86_SMAP), --uaccess) \
$(if $(part-of-module), --module) \
$(if $(CONFIG_GCOV_KERNEL), --no-unreachable)
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 1be01163a9c5..33f14fe1ddde 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -141,11 +141,14 @@ objtool_link()
objtoolopt="${objtoolopt} --stackval"
fi

+ if is_enabled CONFIG_HAVE_STATIC_CALL_INLINE; then
+ objtoolopt="${objtoolopt} --static-call"
+ fi
+
if is_enabled CONFIG_X86_SMAP; then
objtoolopt="${objtoolopt} --uaccess"
fi

-
objtoolopt="${objtoolopt} --lto"
fi

diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index 30971cc50c63..c8c4d2bab42f 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -40,6 +40,7 @@ const struct option check_options[] = {
OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate retpoline usage"),
OPT_BOOLEAN('l', "sls", &opts.sls, "validate straight-line-speculation mitigations"),
OPT_BOOLEAN('s', "stackval", &opts.stackval, "validate frame pointer rules"),
+ OPT_BOOLEAN('t', "static-call", &opts.static_call, "annotate static calls"),
OPT_BOOLEAN('u', "uaccess", &opts.uaccess, "validate uaccess rules for SMAP"),
OPT_CALLBACK_OPTARG(0, "dump", NULL, NULL, "orc", "dump metadata", parse_dump),

@@ -93,6 +94,7 @@ static bool opts_valid(void)
opts.retpoline ||
opts.sls ||
opts.stackval ||
+ opts.static_call ||
opts.uaccess) {
if (opts.dump_orc) {
fprintf(stderr, "--dump can't be combined with other options\n");
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 81688f6c46c0..ffb843ef372d 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -3970,10 +3970,12 @@ int check(struct objtool_file *file)
warnings += ret;
}

- ret = create_static_call_sections(file);
- if (ret < 0)
- goto out;
- warnings += ret;
+ if (opts.static_call) {
+ ret = create_static_call_sections(file);
+ if (ret < 0)
+ goto out;
+ warnings += ret;
+ }

if (opts.retpoline) {
ret = create_retpoline_sites_sections(file);
diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h
index 24a7ff4f37cc..dc4757205b8d 100644
--- a/tools/objtool/include/objtool/builtin.h
+++ b/tools/objtool/include/objtool/builtin.h
@@ -19,6 +19,7 @@ struct opts {
bool retpoline;
bool sls;
bool stackval;
+ bool static_call;
bool uaccess;

/* options: */
--
2.34.1