summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2019-02-25 06:50:09 -0500
committerIngo Molnar <mingo@kernel.org>2019-04-03 05:02:24 -0400
commitea24213d8088f9da73e1b6aadf7abd2435b70397 (patch)
treefba1e181531f8f20ff04ed6a57e10b8bd2805343
parent54262aa2830151f89699fa8a6c5aa05f0992e672 (diff)
objtool: Add UACCESS validation
It is important that UACCESS regions are as small as possible; furthermore the UACCESS state is not scheduled, so doing anything that might directly call into the scheduler will cause random code to be ran with UACCESS enabled. Teach objtool too track UACCESS state and warn about any CALL made while UACCESS is enabled. This very much includes the __fentry__() and __preempt_schedule() calls. Note that exceptions _do_ save/restore the UACCESS state, and therefore they can drive preemption. This also means that all exception handlers must have an otherwise redundant UACCESS disable instruction; therefore ignore this warning for !STT_FUNC code (exception handlers are not normal functions). Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Borislav Petkov <bp@alien8.de> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--scripts/Makefile.build3
-rw-r--r--tools/objtool/arch.h6
-rw-r--r--tools/objtool/arch/x86/decode.c13
-rw-r--r--tools/objtool/builtin-check.c3
-rw-r--r--tools/objtool/builtin.h2
-rw-r--r--tools/objtool/check.c197
-rw-r--r--tools/objtool/check.h3
-rw-r--r--tools/objtool/elf.h1
-rw-r--r--tools/objtool/special.c18
-rw-r--r--tools/objtool/special.h1
10 files changed, 226 insertions, 21 deletions
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 76ca30cc4791..0c5969fa795f 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -222,6 +222,9 @@ endif
222ifdef CONFIG_RETPOLINE 222ifdef CONFIG_RETPOLINE
223 objtool_args += --retpoline 223 objtool_args += --retpoline
224endif 224endif
225ifdef CONFIG_X86_SMAP
226 objtool_args += --uaccess
227endif
225 228
226# 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory 229# 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory
227# 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file 230# 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file
diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h
index b0d7dc3d71b5..467c2fe798a9 100644
--- a/tools/objtool/arch.h
+++ b/tools/objtool/arch.h
@@ -33,7 +33,9 @@
33#define INSN_STACK 8 33#define INSN_STACK 8
34#define INSN_BUG 9 34#define INSN_BUG 9
35#define INSN_NOP 10 35#define INSN_NOP 10
36#define INSN_OTHER 11 36#define INSN_STAC 11
37#define INSN_CLAC 12
38#define INSN_OTHER 13
37#define INSN_LAST INSN_OTHER 39#define INSN_LAST INSN_OTHER
38 40
39enum op_dest_type { 41enum op_dest_type {
@@ -41,6 +43,7 @@ enum op_dest_type {
41 OP_DEST_REG_INDIRECT, 43 OP_DEST_REG_INDIRECT,
42 OP_DEST_MEM, 44 OP_DEST_MEM,
43 OP_DEST_PUSH, 45 OP_DEST_PUSH,
46 OP_DEST_PUSHF,
44 OP_DEST_LEAVE, 47 OP_DEST_LEAVE,
45}; 48};
46 49
@@ -55,6 +58,7 @@ enum op_src_type {
55 OP_SRC_REG_INDIRECT, 58 OP_SRC_REG_INDIRECT,
56 OP_SRC_CONST, 59 OP_SRC_CONST,
57 OP_SRC_POP, 60 OP_SRC_POP,
61 OP_SRC_POPF,
58 OP_SRC_ADD, 62 OP_SRC_ADD,
59 OP_SRC_AND, 63 OP_SRC_AND,
60}; 64};
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c
index 540a209b78ab..ab20a96fee50 100644
--- a/tools/objtool/arch/x86/decode.c
+++ b/tools/objtool/arch/x86/decode.c
@@ -357,19 +357,26 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
357 /* pushf */ 357 /* pushf */
358 *type = INSN_STACK; 358 *type = INSN_STACK;
359 op->src.type = OP_SRC_CONST; 359 op->src.type = OP_SRC_CONST;
360 op->dest.type = OP_DEST_PUSH; 360 op->dest.type = OP_DEST_PUSHF;
361 break; 361 break;
362 362
363 case 0x9d: 363 case 0x9d:
364 /* popf */ 364 /* popf */
365 *type = INSN_STACK; 365 *type = INSN_STACK;
366 op->src.type = OP_SRC_POP; 366 op->src.type = OP_SRC_POPF;
367 op->dest.type = OP_DEST_MEM; 367 op->dest.type = OP_DEST_MEM;
368 break; 368 break;
369 369
370 case 0x0f: 370 case 0x0f:
371 371
372 if (op2 >= 0x80 && op2 <= 0x8f) { 372 if (op2 == 0x01) {
373
374 if (modrm == 0xca)
375 *type = INSN_CLAC;
376 else if (modrm == 0xcb)
377 *type = INSN_STAC;
378
379 } else if (op2 >= 0x80 && op2 <= 0x8f) {
373 380
374 *type = INSN_JUMP_CONDITIONAL; 381 *type = INSN_JUMP_CONDITIONAL;
375 382
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index 99f10c585cbe..f3b378126011 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
32bool no_fp, no_unreachable, retpoline, module, backtrace; 32bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess;
33 33
34static const char * const check_usage[] = { 34static const char * const check_usage[] = {
35 "objtool check [<options>] file.o", 35 "objtool check [<options>] file.o",
@@ -42,6 +42,7 @@ const struct option check_options[] = {
42 OPT_BOOLEAN('r', "retpoline", &retpoline, "Validate retpoline assumptions"), 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"), 43 OPT_BOOLEAN('m', "module", &module, "Indicates the object will be part of a kernel module"),
44 OPT_BOOLEAN('b', "backtrace", &backtrace, "unwind on error"), 44 OPT_BOOLEAN('b', "backtrace", &backtrace, "unwind on error"),
45 OPT_BOOLEAN('a', "uaccess", &uaccess, "enable uaccess checking"),
45 OPT_END(), 46 OPT_END(),
46}; 47};
47 48
diff --git a/tools/objtool/builtin.h b/tools/objtool/builtin.h
index 65fd3cc3c98b..69762f9c5602 100644
--- a/tools/objtool/builtin.h
+++ b/tools/objtool/builtin.h
@@ -20,7 +20,7 @@
20#include <subcmd/parse-options.h> 20#include <subcmd/parse-options.h>
21 21
22extern const struct option check_options[]; 22extern const struct option check_options[];
23extern bool no_fp, no_unreachable, retpoline, module, backtrace; 23extern bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess;
24 24
25extern int cmd_check(int argc, const char **argv); 25extern int cmd_check(int argc, const char **argv);
26extern int cmd_orc(int argc, const char **argv); 26extern int cmd_orc(int argc, const char **argv);
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 8118361295dd..965e954e07f4 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -443,6 +443,82 @@ static void add_ignores(struct objtool_file *file)
443} 443}
444 444
445/* 445/*
446 * This is a whitelist of functions that is allowed to be called with AC set.
447 * The list is meant to be minimal and only contains compiler instrumentation
448 * ABI and a few functions used to implement *_{to,from}_user() functions.
449 *
450 * These functions must not directly change AC, but may PUSHF/POPF.
451 */
452static const char *uaccess_safe_builtin[] = {
453 /* KASAN */
454 "kasan_report",
455 "check_memory_region",
456 /* KASAN out-of-line */
457 "__asan_loadN_noabort",
458 "__asan_load1_noabort",
459 "__asan_load2_noabort",
460 "__asan_load4_noabort",
461 "__asan_load8_noabort",
462 "__asan_load16_noabort",
463 "__asan_storeN_noabort",
464 "__asan_store1_noabort",
465 "__asan_store2_noabort",
466 "__asan_store4_noabort",
467 "__asan_store8_noabort",
468 "__asan_store16_noabort",
469 /* KASAN in-line */
470 "__asan_report_load_n_noabort",
471 "__asan_report_load1_noabort",
472 "__asan_report_load2_noabort",
473 "__asan_report_load4_noabort",
474 "__asan_report_load8_noabort",
475 "__asan_report_load16_noabort",
476 "__asan_report_store_n_noabort",
477 "__asan_report_store1_noabort",
478 "__asan_report_store2_noabort",
479 "__asan_report_store4_noabort",
480 "__asan_report_store8_noabort",
481 "__asan_report_store16_noabort",
482 /* KCOV */
483 "write_comp_data",
484 "__sanitizer_cov_trace_pc",
485 "__sanitizer_cov_trace_const_cmp1",
486 "__sanitizer_cov_trace_const_cmp2",
487 "__sanitizer_cov_trace_const_cmp4",
488 "__sanitizer_cov_trace_const_cmp8",
489 "__sanitizer_cov_trace_cmp1",
490 "__sanitizer_cov_trace_cmp2",
491 "__sanitizer_cov_trace_cmp4",
492 "__sanitizer_cov_trace_cmp8",
493 /* UBSAN */
494 "ubsan_type_mismatch_common",
495 "__ubsan_handle_type_mismatch",
496 "__ubsan_handle_type_mismatch_v1",
497 /* misc */
498 "csum_partial_copy_generic",
499 "__memcpy_mcsafe",
500 "ftrace_likely_update", /* CONFIG_TRACE_BRANCH_PROFILING */
501 NULL
502};
503
504static void add_uaccess_safe(struct objtool_file *file)
505{
506 struct symbol *func;
507 const char **name;
508
509 if (!uaccess)
510 return;
511
512 for (name = uaccess_safe_builtin; *name; name++) {
513 func = find_symbol_by_name(file->elf, *name);
514 if (!func)
515 continue;
516
517 func->alias->uaccess_safe = true;
518 }
519}
520
521/*
446 * FIXME: For now, just ignore any alternatives which add retpolines. This is 522 * FIXME: For now, just ignore any alternatives which add retpolines. This is
447 * a temporary hack, as it doesn't allow ORC to unwind from inside a retpoline. 523 * a temporary hack, as it doesn't allow ORC to unwind from inside a retpoline.
448 * But it at least allows objtool to understand the control flow *around* the 524 * But it at least allows objtool to understand the control flow *around* the
@@ -818,6 +894,7 @@ static int add_special_section_alts(struct objtool_file *file)
818 894
819 alt->insn = new_insn; 895 alt->insn = new_insn;
820 alt->skip_orig = special_alt->skip_orig; 896 alt->skip_orig = special_alt->skip_orig;
897 orig_insn->ignore_alts |= special_alt->skip_alt;
821 list_add_tail(&alt->list, &orig_insn->alts); 898 list_add_tail(&alt->list, &orig_insn->alts);
822 899
823 list_del(&special_alt->list); 900 list_del(&special_alt->list);
@@ -1239,6 +1316,7 @@ static int decode_sections(struct objtool_file *file)
1239 return ret; 1316 return ret;
1240 1317
1241 add_ignores(file); 1318 add_ignores(file);
1319 add_uaccess_safe(file);
1242 1320
1243 ret = add_ignore_alternatives(file); 1321 ret = add_ignore_alternatives(file);
1244 if (ret) 1322 if (ret)
@@ -1320,11 +1398,11 @@ static int update_insn_state_regs(struct instruction *insn, struct insn_state *s
1320 return 0; 1398 return 0;
1321 1399
1322 /* push */ 1400 /* push */
1323 if (op->dest.type == OP_DEST_PUSH) 1401 if (op->dest.type == OP_DEST_PUSH || op->dest.type == OP_DEST_PUSHF)
1324 cfa->offset += 8; 1402 cfa->offset += 8;
1325 1403
1326 /* pop */ 1404 /* pop */
1327 if (op->src.type == OP_SRC_POP) 1405 if (op->src.type == OP_SRC_POP || op->src.type == OP_SRC_POPF)
1328 cfa->offset -= 8; 1406 cfa->offset -= 8;
1329 1407
1330 /* add immediate to sp */ 1408 /* add immediate to sp */
@@ -1581,6 +1659,7 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state)
1581 break; 1659 break;
1582 1660
1583 case OP_SRC_POP: 1661 case OP_SRC_POP:
1662 case OP_SRC_POPF:
1584 if (!state->drap && op->dest.type == OP_DEST_REG && 1663 if (!state->drap && op->dest.type == OP_DEST_REG &&
1585 op->dest.reg == cfa->base) { 1664 op->dest.reg == cfa->base) {
1586 1665
@@ -1645,6 +1724,7 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state)
1645 break; 1724 break;
1646 1725
1647 case OP_DEST_PUSH: 1726 case OP_DEST_PUSH:
1727 case OP_DEST_PUSHF:
1648 state->stack_size += 8; 1728 state->stack_size += 8;
1649 if (cfa->base == CFI_SP) 1729 if (cfa->base == CFI_SP)
1650 cfa->offset += 8; 1730 cfa->offset += 8;
@@ -1735,7 +1815,7 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state)
1735 break; 1815 break;
1736 1816
1737 case OP_DEST_MEM: 1817 case OP_DEST_MEM:
1738 if (op->src.type != OP_SRC_POP) { 1818 if (op->src.type != OP_SRC_POP && op->src.type != OP_SRC_POPF) {
1739 WARN_FUNC("unknown stack-related memory operation", 1819 WARN_FUNC("unknown stack-related memory operation",
1740 insn->sec, insn->offset); 1820 insn->sec, insn->offset);
1741 return -1; 1821 return -1;
@@ -1799,6 +1879,33 @@ static bool insn_state_match(struct instruction *insn, struct insn_state *state)
1799 return false; 1879 return false;
1800} 1880}
1801 1881
1882static inline bool func_uaccess_safe(struct symbol *func)
1883{
1884 if (func)
1885 return func->alias->uaccess_safe;
1886
1887 return false;
1888}
1889
1890static inline const char *insn_dest_name(struct instruction *insn)
1891{
1892 if (insn->call_dest)
1893 return insn->call_dest->name;
1894
1895 return "{dynamic}";
1896}
1897
1898static int validate_call(struct instruction *insn, struct insn_state *state)
1899{
1900 if (state->uaccess && !func_uaccess_safe(insn->call_dest)) {
1901 WARN_FUNC("call to %s() with UACCESS enabled",
1902 insn->sec, insn->offset, insn_dest_name(insn));
1903 return 1;
1904 }
1905
1906 return 0;
1907}
1908
1802static int validate_sibling_call(struct instruction *insn, struct insn_state *state) 1909static int validate_sibling_call(struct instruction *insn, struct insn_state *state)
1803{ 1910{
1804 if (has_modified_stack_frame(state)) { 1911 if (has_modified_stack_frame(state)) {
@@ -1807,7 +1914,7 @@ static int validate_sibling_call(struct instruction *insn, struct insn_state *st
1807 return 1; 1914 return 1;
1808 } 1915 }
1809 1916
1810 return 0; 1917 return validate_call(insn, state);
1811} 1918}
1812 1919
1813/* 1920/*
@@ -1855,7 +1962,9 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
1855 if (!insn->hint && !insn_state_match(insn, &state)) 1962 if (!insn->hint && !insn_state_match(insn, &state))
1856 return 1; 1963 return 1;
1857 1964
1858 return 0; 1965 /* If we were here with AC=0, but now have AC=1, go again */
1966 if (insn->state.uaccess || !state.uaccess)
1967 return 0;
1859 } 1968 }
1860 1969
1861 if (insn->hint) { 1970 if (insn->hint) {
@@ -1925,6 +2034,16 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
1925 switch (insn->type) { 2034 switch (insn->type) {
1926 2035
1927 case INSN_RETURN: 2036 case INSN_RETURN:
2037 if (state.uaccess && !func_uaccess_safe(func)) {
2038 WARN_FUNC("return with UACCESS enabled", sec, insn->offset);
2039 return 1;
2040 }
2041
2042 if (!state.uaccess && func_uaccess_safe(func)) {
2043 WARN_FUNC("return with UACCESS disabled from a UACCESS-safe function", sec, insn->offset);
2044 return 1;
2045 }
2046
1928 if (func && has_modified_stack_frame(&state)) { 2047 if (func && has_modified_stack_frame(&state)) {
1929 WARN_FUNC("return with modified stack frame", 2048 WARN_FUNC("return with modified stack frame",
1930 sec, insn->offset); 2049 sec, insn->offset);
@@ -1940,17 +2059,22 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
1940 return 0; 2059 return 0;
1941 2060
1942 case INSN_CALL: 2061 case INSN_CALL:
1943 if (is_fentry_call(insn)) 2062 case INSN_CALL_DYNAMIC:
1944 break; 2063 ret = validate_call(insn, &state);
2064 if (ret)
2065 return ret;
1945 2066
1946 ret = dead_end_function(file, insn->call_dest); 2067 if (insn->type == INSN_CALL) {
1947 if (ret == 1) 2068 if (is_fentry_call(insn))
1948 return 0; 2069 break;
1949 if (ret == -1) 2070
1950 return 1; 2071 ret = dead_end_function(file, insn->call_dest);
2072 if (ret == 1)
2073 return 0;
2074 if (ret == -1)
2075 return 1;
2076 }
1951 2077
1952 /* fallthrough */
1953 case INSN_CALL_DYNAMIC:
1954 if (!no_fp && func && !has_valid_stack_frame(&state)) { 2078 if (!no_fp && func && !has_valid_stack_frame(&state)) {
1955 WARN_FUNC("call without frame pointer save/setup", 2079 WARN_FUNC("call without frame pointer save/setup",
1956 sec, insn->offset); 2080 sec, insn->offset);
@@ -2003,6 +2127,49 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
2003 if (update_insn_state(insn, &state)) 2127 if (update_insn_state(insn, &state))
2004 return 1; 2128 return 1;
2005 2129
2130 if (insn->stack_op.dest.type == OP_DEST_PUSHF) {
2131 if (!state.uaccess_stack) {
2132 state.uaccess_stack = 1;
2133 } else if (state.uaccess_stack >> 31) {
2134 WARN_FUNC("PUSHF stack exhausted", sec, insn->offset);
2135 return 1;
2136 }
2137 state.uaccess_stack <<= 1;
2138 state.uaccess_stack |= state.uaccess;
2139 }
2140
2141 if (insn->stack_op.src.type == OP_SRC_POPF) {
2142 if (state.uaccess_stack) {
2143 state.uaccess = state.uaccess_stack & 1;
2144 state.uaccess_stack >>= 1;
2145 if (state.uaccess_stack == 1)
2146 state.uaccess_stack = 0;
2147 }
2148 }
2149
2150 break;
2151
2152 case INSN_STAC:
2153 if (state.uaccess) {
2154 WARN_FUNC("recursive UACCESS enable", sec, insn->offset);
2155 return 1;
2156 }
2157
2158 state.uaccess = true;
2159 break;
2160
2161 case INSN_CLAC:
2162 if (!state.uaccess && insn->func) {
2163 WARN_FUNC("redundant UACCESS disable", sec, insn->offset);
2164 return 1;
2165 }
2166
2167 if (func_uaccess_safe(func) && !state.uaccess_stack) {
2168 WARN_FUNC("UACCESS-safe disables UACCESS", sec, insn->offset);
2169 return 1;
2170 }
2171
2172 state.uaccess = false;
2006 break; 2173 break;
2007 2174
2008 default: 2175 default:
@@ -2168,6 +2335,8 @@ static int validate_functions(struct objtool_file *file)
2168 if (!insn || insn->ignore) 2335 if (!insn || insn->ignore)
2169 continue; 2336 continue;
2170 2337
2338 state.uaccess = func->alias->uaccess_safe;
2339
2171 ret = validate_branch(file, insn, state); 2340 ret = validate_branch(file, insn, state);
2172 if (ret && backtrace) 2341 if (ret && backtrace)
2173 BT_FUNC("<=== (func)", insn); 2342 BT_FUNC("<=== (func)", insn);
diff --git a/tools/objtool/check.h b/tools/objtool/check.h
index d8896eb43521..78a95d06c165 100644
--- a/tools/objtool/check.h
+++ b/tools/objtool/check.h
@@ -31,7 +31,8 @@ struct insn_state {
31 int stack_size; 31 int stack_size;
32 unsigned char type; 32 unsigned char type;
33 bool bp_scratch; 33 bool bp_scratch;
34 bool drap, end; 34 bool drap, end, uaccess;
35 unsigned int uaccess_stack;
35 int drap_reg, drap_offset; 36 int drap_reg, drap_offset;
36 struct cfi_reg vals[CFI_NUM_REGS]; 37 struct cfi_reg vals[CFI_NUM_REGS];
37}; 38};
diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h
index 968265b4b4cd..2cc2ed49322d 100644
--- a/tools/objtool/elf.h
+++ b/tools/objtool/elf.h
@@ -62,6 +62,7 @@ struct symbol {
62 unsigned long offset; 62 unsigned long offset;
63 unsigned int len; 63 unsigned int len;
64 struct symbol *pfunc, *cfunc, *alias; 64 struct symbol *pfunc, *cfunc, *alias;
65 bool uaccess_safe;
65}; 66};
66 67
67struct rela { 68struct rela {
diff --git a/tools/objtool/special.c b/tools/objtool/special.c
index 50af4e1274b3..4e50563d87c6 100644
--- a/tools/objtool/special.c
+++ b/tools/objtool/special.c
@@ -23,6 +23,7 @@
23#include <stdlib.h> 23#include <stdlib.h>
24#include <string.h> 24#include <string.h>
25 25
26#include "builtin.h"
26#include "special.h" 27#include "special.h"
27#include "warn.h" 28#include "warn.h"
28 29
@@ -42,6 +43,7 @@
42#define ALT_NEW_LEN_OFFSET 11 43#define ALT_NEW_LEN_OFFSET 11
43 44
44#define X86_FEATURE_POPCNT (4*32+23) 45#define X86_FEATURE_POPCNT (4*32+23)
46#define X86_FEATURE_SMAP (9*32+20)
45 47
46struct special_entry { 48struct special_entry {
47 const char *sec; 49 const char *sec;
@@ -110,6 +112,22 @@ static int get_alt_entry(struct elf *elf, struct special_entry *entry,
110 */ 112 */
111 if (feature == X86_FEATURE_POPCNT) 113 if (feature == X86_FEATURE_POPCNT)
112 alt->skip_orig = true; 114 alt->skip_orig = true;
115
116 /*
117 * If UACCESS validation is enabled; force that alternative;
118 * otherwise force it the other way.
119 *
120 * What we want to avoid is having both the original and the
121 * alternative code flow at the same time, in that case we can
122 * find paths that see the STAC but take the NOP instead of
123 * CLAC and the other way around.
124 */
125 if (feature == X86_FEATURE_SMAP) {
126 if (uaccess)
127 alt->skip_orig = true;
128 else
129 alt->skip_alt = true;
130 }
113 } 131 }
114 132
115 orig_rela = find_rela_by_dest(sec, offset + entry->orig); 133 orig_rela = find_rela_by_dest(sec, offset + entry->orig);
diff --git a/tools/objtool/special.h b/tools/objtool/special.h
index fad1d092f679..d5c062e718ef 100644
--- a/tools/objtool/special.h
+++ b/tools/objtool/special.h
@@ -26,6 +26,7 @@ struct special_alt {
26 26
27 bool group; 27 bool group;
28 bool skip_orig; 28 bool skip_orig;
29 bool skip_alt;
29 bool jump_or_nop; 30 bool jump_or_nop;
30 31
31 struct section *orig_sec; 32 struct section *orig_sec;