diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-26 12:34:21 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-26 12:34:21 -0500 |
commit | 85a2d939c05965ab9e849735436a3c8d3538dc75 (patch) | |
tree | ba5436dc3c687dc84b22536824b68ab413fc7c4a /tools | |
parent | d4858aaf6bd8a90e2dacc0dfec2077e334dcedbf (diff) | |
parent | 946fbbc13dce68902f64515b610eeb2a6c3d7a64 (diff) |
Merge branch 'x86-pti-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fixes from Thomas Gleixner:
"Yet another pile of melted spectrum related changes:
- sanitize the array_index_nospec protection mechanism: Remove the
overengineered array_index_nospec_mask_check() magic and allow
const-qualified types as index to avoid temporary storage in a
non-const local variable.
- make the microcode loader more robust by properly propagating error
codes. Provide information about new feature bits after micro code
was updated so administrators can act upon.
- optimizations of the entry ASM code which reduce code footprint and
make the code simpler and faster.
- fix the {pmd,pud}_{set,clear}_flags() implementations to work
properly on paravirt kernels by removing the address translation
operations.
- revert the harmful vmexit_fill_RSB() optimization
- use IBRS around firmware calls
- teach objtool about retpolines and add annotations for indirect
jumps and calls.
- explicitly disable jumplabel patching in __init code and handle
patching failures properly instead of silently ignoring them.
- remove indirect paravirt calls for writing the speculation control
MSR as these calls are obviously proving the same attack vector
which is tried to be mitigated.
- a few small fixes which address build issues with recent compiler
and assembler versions"
* 'x86-pti-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (38 commits)
KVM/VMX: Optimize vmx_vcpu_run() and svm_vcpu_run() by marking the RDMSR path as unlikely()
KVM/x86: Remove indirect MSR op calls from SPEC_CTRL
objtool, retpolines: Integrate objtool with retpoline support more closely
x86/entry/64: Simplify ENCODE_FRAME_POINTER
extable: Make init_kernel_text() global
jump_label: Warn on failed jump_label patching attempt
jump_label: Explicitly disable jump labels in __init code
x86/entry/64: Open-code switch_to_thread_stack()
x86/entry/64: Move ASM_CLAC to interrupt_entry()
x86/entry/64: Remove 'interrupt' macro
x86/entry/64: Move the switch_to_thread_stack() call to interrupt_entry()
x86/entry/64: Move ENTER_IRQ_STACK from interrupt macro to interrupt_entry
x86/entry/64: Move PUSH_AND_CLEAR_REGS from interrupt macro to helper function
x86/speculation: Move firmware_restrict_branch_speculation_*() from C to CPP
objtool: Add module specific retpoline rules
objtool: Add retpoline validation
objtool: Use existing global variables for options
x86/mm/sme, objtool: Annotate indirect call in sme_encrypt_execute()
x86/boot, objtool: Annotate indirect jump in secondary_startup_64()
x86/paravirt, objtool: Annotate indirect calls
...
Diffstat (limited to 'tools')
-rw-r--r-- | tools/objtool/builtin-check.c | 6 | ||||
-rw-r--r-- | tools/objtool/builtin-orc.c | 6 | ||||
-rw-r--r-- | tools/objtool/builtin.h | 5 | ||||
-rw-r--r-- | tools/objtool/check.c | 100 | ||||
-rw-r--r-- | tools/objtool/check.h | 3 |
5 files changed, 108 insertions, 12 deletions
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index 57254f5b2779..694abc628e9b 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c | |||
@@ -29,7 +29,7 @@ | |||
29 | #include "builtin.h" | 29 | #include "builtin.h" |
30 | #include "check.h" | 30 | #include "check.h" |
31 | 31 | ||
32 | bool no_fp, no_unreachable; | 32 | bool no_fp, no_unreachable, retpoline, module; |
33 | 33 | ||
34 | static const char * const check_usage[] = { | 34 | static const char * const check_usage[] = { |
35 | "objtool check [<options>] file.o", | 35 | "objtool check [<options>] file.o", |
@@ -39,6 +39,8 @@ static const char * const check_usage[] = { | |||
39 | const struct option check_options[] = { | 39 | const struct option check_options[] = { |
40 | OPT_BOOLEAN('f', "no-fp", &no_fp, "Skip frame pointer validation"), | 40 | OPT_BOOLEAN('f', "no-fp", &no_fp, "Skip frame pointer validation"), |
41 | OPT_BOOLEAN('u', "no-unreachable", &no_unreachable, "Skip 'unreachable instruction' warnings"), | 41 | OPT_BOOLEAN('u', "no-unreachable", &no_unreachable, "Skip 'unreachable instruction' warnings"), |
42 | OPT_BOOLEAN('r', "retpoline", &retpoline, "Validate retpoline assumptions"), | ||
43 | OPT_BOOLEAN('m', "module", &module, "Indicates the object will be part of a kernel module"), | ||
42 | OPT_END(), | 44 | OPT_END(), |
43 | }; | 45 | }; |
44 | 46 | ||
@@ -53,5 +55,5 @@ int cmd_check(int argc, const char **argv) | |||
53 | 55 | ||
54 | objname = argv[0]; | 56 | objname = argv[0]; |
55 | 57 | ||
56 | return check(objname, no_fp, no_unreachable, false); | 58 | return check(objname, false); |
57 | } | 59 | } |
diff --git a/tools/objtool/builtin-orc.c b/tools/objtool/builtin-orc.c index 91e8e19ff5e0..77ea2b97117d 100644 --- a/tools/objtool/builtin-orc.c +++ b/tools/objtool/builtin-orc.c | |||
@@ -25,7 +25,6 @@ | |||
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <string.h> | 27 | #include <string.h> |
28 | #include <subcmd/parse-options.h> | ||
29 | #include "builtin.h" | 28 | #include "builtin.h" |
30 | #include "check.h" | 29 | #include "check.h" |
31 | 30 | ||
@@ -36,9 +35,6 @@ static const char *orc_usage[] = { | |||
36 | NULL, | 35 | NULL, |
37 | }; | 36 | }; |
38 | 37 | ||
39 | extern const struct option check_options[]; | ||
40 | extern bool no_fp, no_unreachable; | ||
41 | |||
42 | int cmd_orc(int argc, const char **argv) | 38 | int cmd_orc(int argc, const char **argv) |
43 | { | 39 | { |
44 | const char *objname; | 40 | const char *objname; |
@@ -54,7 +50,7 @@ int cmd_orc(int argc, const char **argv) | |||
54 | 50 | ||
55 | objname = argv[0]; | 51 | objname = argv[0]; |
56 | 52 | ||
57 | return check(objname, no_fp, no_unreachable, true); | 53 | return check(objname, true); |
58 | } | 54 | } |
59 | 55 | ||
60 | if (!strcmp(argv[0], "dump")) { | 56 | if (!strcmp(argv[0], "dump")) { |
diff --git a/tools/objtool/builtin.h b/tools/objtool/builtin.h index dd526067fed5..28ff40e19a14 100644 --- a/tools/objtool/builtin.h +++ b/tools/objtool/builtin.h | |||
@@ -17,6 +17,11 @@ | |||
17 | #ifndef _BUILTIN_H | 17 | #ifndef _BUILTIN_H |
18 | #define _BUILTIN_H | 18 | #define _BUILTIN_H |
19 | 19 | ||
20 | #include <subcmd/parse-options.h> | ||
21 | |||
22 | extern const struct option check_options[]; | ||
23 | extern bool no_fp, no_unreachable, retpoline, module; | ||
24 | |||
20 | extern int cmd_check(int argc, const char **argv); | 25 | extern int cmd_check(int argc, const char **argv); |
21 | extern int cmd_orc(int argc, const char **argv); | 26 | extern int cmd_orc(int argc, const char **argv); |
22 | 27 | ||
diff --git a/tools/objtool/check.c b/tools/objtool/check.c index a8cb69a26576..472e64e95891 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <string.h> | 18 | #include <string.h> |
19 | #include <stdlib.h> | 19 | #include <stdlib.h> |
20 | 20 | ||
21 | #include "builtin.h" | ||
21 | #include "check.h" | 22 | #include "check.h" |
22 | #include "elf.h" | 23 | #include "elf.h" |
23 | #include "special.h" | 24 | #include "special.h" |
@@ -33,7 +34,6 @@ struct alternative { | |||
33 | }; | 34 | }; |
34 | 35 | ||
35 | const char *objname; | 36 | const char *objname; |
36 | static bool no_fp; | ||
37 | struct cfi_state initial_func_cfi; | 37 | struct cfi_state initial_func_cfi; |
38 | 38 | ||
39 | struct instruction *find_insn(struct objtool_file *file, | 39 | struct instruction *find_insn(struct objtool_file *file, |
@@ -497,6 +497,7 @@ static int add_jump_destinations(struct objtool_file *file) | |||
497 | * disguise, so convert them accordingly. | 497 | * disguise, so convert them accordingly. |
498 | */ | 498 | */ |
499 | insn->type = INSN_JUMP_DYNAMIC; | 499 | insn->type = INSN_JUMP_DYNAMIC; |
500 | insn->retpoline_safe = true; | ||
500 | continue; | 501 | continue; |
501 | } else { | 502 | } else { |
502 | /* sibling call */ | 503 | /* sibling call */ |
@@ -548,7 +549,8 @@ static int add_call_destinations(struct objtool_file *file) | |||
548 | if (!insn->call_dest && !insn->ignore) { | 549 | if (!insn->call_dest && !insn->ignore) { |
549 | WARN_FUNC("unsupported intra-function call", | 550 | WARN_FUNC("unsupported intra-function call", |
550 | insn->sec, insn->offset); | 551 | insn->sec, insn->offset); |
551 | WARN("If this is a retpoline, please patch it in with alternatives and annotate it with ANNOTATE_NOSPEC_ALTERNATIVE."); | 552 | if (retpoline) |
553 | WARN("If this is a retpoline, please patch it in with alternatives and annotate it with ANNOTATE_NOSPEC_ALTERNATIVE."); | ||
552 | return -1; | 554 | return -1; |
553 | } | 555 | } |
554 | 556 | ||
@@ -1108,6 +1110,54 @@ static int read_unwind_hints(struct objtool_file *file) | |||
1108 | return 0; | 1110 | return 0; |
1109 | } | 1111 | } |
1110 | 1112 | ||
1113 | static int read_retpoline_hints(struct objtool_file *file) | ||
1114 | { | ||
1115 | struct section *sec, *relasec; | ||
1116 | struct instruction *insn; | ||
1117 | struct rela *rela; | ||
1118 | int i; | ||
1119 | |||
1120 | sec = find_section_by_name(file->elf, ".discard.retpoline_safe"); | ||
1121 | if (!sec) | ||
1122 | return 0; | ||
1123 | |||
1124 | relasec = sec->rela; | ||
1125 | if (!relasec) { | ||
1126 | WARN("missing .rela.discard.retpoline_safe section"); | ||
1127 | return -1; | ||
1128 | } | ||
1129 | |||
1130 | if (sec->len % sizeof(unsigned long)) { | ||
1131 | WARN("retpoline_safe size mismatch: %d %ld", sec->len, sizeof(unsigned long)); | ||
1132 | return -1; | ||
1133 | } | ||
1134 | |||
1135 | for (i = 0; i < sec->len / sizeof(unsigned long); i++) { | ||
1136 | rela = find_rela_by_dest(sec, i * sizeof(unsigned long)); | ||
1137 | if (!rela) { | ||
1138 | WARN("can't find rela for retpoline_safe[%d]", i); | ||
1139 | return -1; | ||
1140 | } | ||
1141 | |||
1142 | insn = find_insn(file, rela->sym->sec, rela->addend); | ||
1143 | if (!insn) { | ||
1144 | WARN("can't find insn for retpoline_safe[%d]", i); | ||
1145 | return -1; | ||
1146 | } | ||
1147 | |||
1148 | if (insn->type != INSN_JUMP_DYNAMIC && | ||
1149 | insn->type != INSN_CALL_DYNAMIC) { | ||
1150 | WARN_FUNC("retpoline_safe hint not a indirect jump/call", | ||
1151 | insn->sec, insn->offset); | ||
1152 | return -1; | ||
1153 | } | ||
1154 | |||
1155 | insn->retpoline_safe = true; | ||
1156 | } | ||
1157 | |||
1158 | return 0; | ||
1159 | } | ||
1160 | |||
1111 | static int decode_sections(struct objtool_file *file) | 1161 | static int decode_sections(struct objtool_file *file) |
1112 | { | 1162 | { |
1113 | int ret; | 1163 | int ret; |
@@ -1146,6 +1196,10 @@ static int decode_sections(struct objtool_file *file) | |||
1146 | if (ret) | 1196 | if (ret) |
1147 | return ret; | 1197 | return ret; |
1148 | 1198 | ||
1199 | ret = read_retpoline_hints(file); | ||
1200 | if (ret) | ||
1201 | return ret; | ||
1202 | |||
1149 | return 0; | 1203 | return 0; |
1150 | } | 1204 | } |
1151 | 1205 | ||
@@ -1891,6 +1945,38 @@ static int validate_unwind_hints(struct objtool_file *file) | |||
1891 | return warnings; | 1945 | return warnings; |
1892 | } | 1946 | } |
1893 | 1947 | ||
1948 | static int validate_retpoline(struct objtool_file *file) | ||
1949 | { | ||
1950 | struct instruction *insn; | ||
1951 | int warnings = 0; | ||
1952 | |||
1953 | for_each_insn(file, insn) { | ||
1954 | if (insn->type != INSN_JUMP_DYNAMIC && | ||
1955 | insn->type != INSN_CALL_DYNAMIC) | ||
1956 | continue; | ||
1957 | |||
1958 | if (insn->retpoline_safe) | ||
1959 | continue; | ||
1960 | |||
1961 | /* | ||
1962 | * .init.text code is ran before userspace and thus doesn't | ||
1963 | * strictly need retpolines, except for modules which are | ||
1964 | * loaded late, they very much do need retpoline in their | ||
1965 | * .init.text | ||
1966 | */ | ||
1967 | if (!strcmp(insn->sec->name, ".init.text") && !module) | ||
1968 | continue; | ||
1969 | |||
1970 | WARN_FUNC("indirect %s found in RETPOLINE build", | ||
1971 | insn->sec, insn->offset, | ||
1972 | insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call"); | ||
1973 | |||
1974 | warnings++; | ||
1975 | } | ||
1976 | |||
1977 | return warnings; | ||
1978 | } | ||
1979 | |||
1894 | static bool is_kasan_insn(struct instruction *insn) | 1980 | static bool is_kasan_insn(struct instruction *insn) |
1895 | { | 1981 | { |
1896 | return (insn->type == INSN_CALL && | 1982 | return (insn->type == INSN_CALL && |
@@ -2022,13 +2108,12 @@ static void cleanup(struct objtool_file *file) | |||
2022 | elf_close(file->elf); | 2108 | elf_close(file->elf); |
2023 | } | 2109 | } |
2024 | 2110 | ||
2025 | int check(const char *_objname, bool _no_fp, bool no_unreachable, bool orc) | 2111 | int check(const char *_objname, bool orc) |
2026 | { | 2112 | { |
2027 | struct objtool_file file; | 2113 | struct objtool_file file; |
2028 | int ret, warnings = 0; | 2114 | int ret, warnings = 0; |
2029 | 2115 | ||
2030 | objname = _objname; | 2116 | objname = _objname; |
2031 | no_fp = _no_fp; | ||
2032 | 2117 | ||
2033 | file.elf = elf_open(objname, orc ? O_RDWR : O_RDONLY); | 2118 | file.elf = elf_open(objname, orc ? O_RDWR : O_RDONLY); |
2034 | if (!file.elf) | 2119 | if (!file.elf) |
@@ -2052,6 +2137,13 @@ int check(const char *_objname, bool _no_fp, bool no_unreachable, bool orc) | |||
2052 | if (list_empty(&file.insn_list)) | 2137 | if (list_empty(&file.insn_list)) |
2053 | goto out; | 2138 | goto out; |
2054 | 2139 | ||
2140 | if (retpoline) { | ||
2141 | ret = validate_retpoline(&file); | ||
2142 | if (ret < 0) | ||
2143 | return ret; | ||
2144 | warnings += ret; | ||
2145 | } | ||
2146 | |||
2055 | ret = validate_functions(&file); | 2147 | ret = validate_functions(&file); |
2056 | if (ret < 0) | 2148 | if (ret < 0) |
2057 | goto out; | 2149 | goto out; |
diff --git a/tools/objtool/check.h b/tools/objtool/check.h index 23a1d065cae1..c6b68fcb926f 100644 --- a/tools/objtool/check.h +++ b/tools/objtool/check.h | |||
@@ -45,6 +45,7 @@ struct instruction { | |||
45 | unsigned char type; | 45 | unsigned char type; |
46 | unsigned long immediate; | 46 | unsigned long immediate; |
47 | bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts; | 47 | bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts; |
48 | bool retpoline_safe; | ||
48 | struct symbol *call_dest; | 49 | struct symbol *call_dest; |
49 | struct instruction *jump_dest; | 50 | struct instruction *jump_dest; |
50 | struct instruction *first_jump_src; | 51 | struct instruction *first_jump_src; |
@@ -63,7 +64,7 @@ struct objtool_file { | |||
63 | bool ignore_unreachables, c_file, hints; | 64 | bool ignore_unreachables, c_file, hints; |
64 | }; | 65 | }; |
65 | 66 | ||
66 | int check(const char *objname, bool no_fp, bool no_unreachable, bool orc); | 67 | int check(const char *objname, bool orc); |
67 | 68 | ||
68 | struct instruction *find_insn(struct objtool_file *file, | 69 | struct instruction *find_insn(struct objtool_file *file, |
69 | struct section *sec, unsigned long offset); | 70 | struct section *sec, unsigned long offset); |