diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-03-20 06:27:18 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-03-20 06:27:18 -0400 |
commit | 4958134df54c2c84e9c22ea042761d439164d26e (patch) | |
tree | 503177afab11f7d25b12a84ce25b481d305c51ba /tools/objtool | |
parent | c4f528795d1add8b63652673f7262729f679c6c1 (diff) | |
parent | c698ca5278934c0ae32297a8725ced2e27585d7f (diff) |
Merge 4.16-rc6 into tty-next
We want the serial/tty fixes in here as well.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'tools/objtool')
-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 | 93 | ||||
-rw-r--r-- | tools/objtool/check.h | 3 |
5 files changed, 100 insertions, 13 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..92b6a2c21631 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 | ||
@@ -923,7 +925,11 @@ static struct rela *find_switch_table(struct objtool_file *file, | |||
923 | if (find_symbol_containing(file->rodata, text_rela->addend)) | 925 | if (find_symbol_containing(file->rodata, text_rela->addend)) |
924 | continue; | 926 | continue; |
925 | 927 | ||
926 | return find_rela_by_dest(file->rodata, text_rela->addend); | 928 | rodata_rela = find_rela_by_dest(file->rodata, text_rela->addend); |
929 | if (!rodata_rela) | ||
930 | continue; | ||
931 | |||
932 | return rodata_rela; | ||
927 | } | 933 | } |
928 | 934 | ||
929 | return NULL; | 935 | return NULL; |
@@ -1108,6 +1114,41 @@ static int read_unwind_hints(struct objtool_file *file) | |||
1108 | return 0; | 1114 | return 0; |
1109 | } | 1115 | } |
1110 | 1116 | ||
1117 | static int read_retpoline_hints(struct objtool_file *file) | ||
1118 | { | ||
1119 | struct section *sec; | ||
1120 | struct instruction *insn; | ||
1121 | struct rela *rela; | ||
1122 | |||
1123 | sec = find_section_by_name(file->elf, ".rela.discard.retpoline_safe"); | ||
1124 | if (!sec) | ||
1125 | return 0; | ||
1126 | |||
1127 | list_for_each_entry(rela, &sec->rela_list, list) { | ||
1128 | if (rela->sym->type != STT_SECTION) { | ||
1129 | WARN("unexpected relocation symbol type in %s", sec->name); | ||
1130 | return -1; | ||
1131 | } | ||
1132 | |||
1133 | insn = find_insn(file, rela->sym->sec, rela->addend); | ||
1134 | if (!insn) { | ||
1135 | WARN("bad .discard.retpoline_safe entry"); | ||
1136 | return -1; | ||
1137 | } | ||
1138 | |||
1139 | if (insn->type != INSN_JUMP_DYNAMIC && | ||
1140 | insn->type != INSN_CALL_DYNAMIC) { | ||
1141 | WARN_FUNC("retpoline_safe hint not an indirect jump/call", | ||
1142 | insn->sec, insn->offset); | ||
1143 | return -1; | ||
1144 | } | ||
1145 | |||
1146 | insn->retpoline_safe = true; | ||
1147 | } | ||
1148 | |||
1149 | return 0; | ||
1150 | } | ||
1151 | |||
1111 | static int decode_sections(struct objtool_file *file) | 1152 | static int decode_sections(struct objtool_file *file) |
1112 | { | 1153 | { |
1113 | int ret; | 1154 | int ret; |
@@ -1146,6 +1187,10 @@ static int decode_sections(struct objtool_file *file) | |||
1146 | if (ret) | 1187 | if (ret) |
1147 | return ret; | 1188 | return ret; |
1148 | 1189 | ||
1190 | ret = read_retpoline_hints(file); | ||
1191 | if (ret) | ||
1192 | return ret; | ||
1193 | |||
1149 | return 0; | 1194 | return 0; |
1150 | } | 1195 | } |
1151 | 1196 | ||
@@ -1891,6 +1936,38 @@ static int validate_unwind_hints(struct objtool_file *file) | |||
1891 | return warnings; | 1936 | return warnings; |
1892 | } | 1937 | } |
1893 | 1938 | ||
1939 | static int validate_retpoline(struct objtool_file *file) | ||
1940 | { | ||
1941 | struct instruction *insn; | ||
1942 | int warnings = 0; | ||
1943 | |||
1944 | for_each_insn(file, insn) { | ||
1945 | if (insn->type != INSN_JUMP_DYNAMIC && | ||
1946 | insn->type != INSN_CALL_DYNAMIC) | ||
1947 | continue; | ||
1948 | |||
1949 | if (insn->retpoline_safe) | ||
1950 | continue; | ||
1951 | |||
1952 | /* | ||
1953 | * .init.text code is ran before userspace and thus doesn't | ||
1954 | * strictly need retpolines, except for modules which are | ||
1955 | * loaded late, they very much do need retpoline in their | ||
1956 | * .init.text | ||
1957 | */ | ||
1958 | if (!strcmp(insn->sec->name, ".init.text") && !module) | ||
1959 | continue; | ||
1960 | |||
1961 | WARN_FUNC("indirect %s found in RETPOLINE build", | ||
1962 | insn->sec, insn->offset, | ||
1963 | insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call"); | ||
1964 | |||
1965 | warnings++; | ||
1966 | } | ||
1967 | |||
1968 | return warnings; | ||
1969 | } | ||
1970 | |||
1894 | static bool is_kasan_insn(struct instruction *insn) | 1971 | static bool is_kasan_insn(struct instruction *insn) |
1895 | { | 1972 | { |
1896 | return (insn->type == INSN_CALL && | 1973 | return (insn->type == INSN_CALL && |
@@ -2022,13 +2099,12 @@ static void cleanup(struct objtool_file *file) | |||
2022 | elf_close(file->elf); | 2099 | elf_close(file->elf); |
2023 | } | 2100 | } |
2024 | 2101 | ||
2025 | int check(const char *_objname, bool _no_fp, bool no_unreachable, bool orc) | 2102 | int check(const char *_objname, bool orc) |
2026 | { | 2103 | { |
2027 | struct objtool_file file; | 2104 | struct objtool_file file; |
2028 | int ret, warnings = 0; | 2105 | int ret, warnings = 0; |
2029 | 2106 | ||
2030 | objname = _objname; | 2107 | objname = _objname; |
2031 | no_fp = _no_fp; | ||
2032 | 2108 | ||
2033 | file.elf = elf_open(objname, orc ? O_RDWR : O_RDONLY); | 2109 | file.elf = elf_open(objname, orc ? O_RDWR : O_RDONLY); |
2034 | if (!file.elf) | 2110 | if (!file.elf) |
@@ -2052,6 +2128,13 @@ int check(const char *_objname, bool _no_fp, bool no_unreachable, bool orc) | |||
2052 | if (list_empty(&file.insn_list)) | 2128 | if (list_empty(&file.insn_list)) |
2053 | goto out; | 2129 | goto out; |
2054 | 2130 | ||
2131 | if (retpoline) { | ||
2132 | ret = validate_retpoline(&file); | ||
2133 | if (ret < 0) | ||
2134 | return ret; | ||
2135 | warnings += ret; | ||
2136 | } | ||
2137 | |||
2055 | ret = validate_functions(&file); | 2138 | ret = validate_functions(&file); |
2056 | if (ret < 0) | 2139 | if (ret < 0) |
2057 | goto out; | 2140 | 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); |