summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2019-02-25 05:10:55 -0500
committerIngo Molnar <mingo@kernel.org>2019-04-03 05:02:24 -0400
commit2f0f9e9ad7b3459c5c54ef2c03145a98e65dd158 (patch)
tree6ce2229a931e53504851d1e98b6319630ff952c7
parentea24213d8088f9da73e1b6aadf7abd2435b70397 (diff)
objtool: Add Direction Flag validation
Having DF escape is BAD(tm). Linus; you suggested this one, but since DF really is only used from ASM and the failure case is fairly obvious, do we really need this? OTOH the patch is fairly small and simple, so let's just do this to demonstrate objtool's superior awesomeness. Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Borislav Petkov <bp@alien8.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--tools/objtool/arch.h4
-rw-r--r--tools/objtool/arch/x86/decode.c8
-rw-r--r--tools/objtool/check.c25
-rw-r--r--tools/objtool/check.h2
4 files changed, 37 insertions, 2 deletions
diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h
index 467c2fe798a9..7a111a77b7aa 100644
--- a/tools/objtool/arch.h
+++ b/tools/objtool/arch.h
@@ -35,7 +35,9 @@
35#define INSN_NOP 10 35#define INSN_NOP 10
36#define INSN_STAC 11 36#define INSN_STAC 11
37#define INSN_CLAC 12 37#define INSN_CLAC 12
38#define INSN_OTHER 13 38#define INSN_STD 13
39#define INSN_CLD 14
40#define INSN_OTHER 15
39#define INSN_LAST INSN_OTHER 41#define INSN_LAST INSN_OTHER
40 42
41enum op_dest_type { 43enum op_dest_type {
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c
index ab20a96fee50..472e991f6512 100644
--- a/tools/objtool/arch/x86/decode.c
+++ b/tools/objtool/arch/x86/decode.c
@@ -451,6 +451,14 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
451 *type = INSN_CALL; 451 *type = INSN_CALL;
452 break; 452 break;
453 453
454 case 0xfc:
455 *type = INSN_CLD;
456 break;
457
458 case 0xfd:
459 *type = INSN_STD;
460 break;
461
454 case 0xff: 462 case 0xff:
455 if (modrm_reg == 2 || modrm_reg == 3) 463 if (modrm_reg == 2 || modrm_reg == 3)
456 464
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 965e954e07f4..38b0517dc49e 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1903,6 +1903,12 @@ static int validate_call(struct instruction *insn, struct insn_state *state)
1903 return 1; 1903 return 1;
1904 } 1904 }
1905 1905
1906 if (state->df) {
1907 WARN_FUNC("call to %s() with DF set",
1908 insn->sec, insn->offset, insn_dest_name(insn));
1909 return 1;
1910 }
1911
1906 return 0; 1912 return 0;
1907} 1913}
1908 1914
@@ -2044,6 +2050,11 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
2044 return 1; 2050 return 1;
2045 } 2051 }
2046 2052
2053 if (state.df) {
2054 WARN_FUNC("return with DF set", sec, insn->offset);
2055 return 1;
2056 }
2057
2047 if (func && has_modified_stack_frame(&state)) { 2058 if (func && has_modified_stack_frame(&state)) {
2048 WARN_FUNC("return with modified stack frame", 2059 WARN_FUNC("return with modified stack frame",
2049 sec, insn->offset); 2060 sec, insn->offset);
@@ -2172,6 +2183,20 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
2172 state.uaccess = false; 2183 state.uaccess = false;
2173 break; 2184 break;
2174 2185
2186 case INSN_STD:
2187 if (state.df)
2188 WARN_FUNC("recursive STD", sec, insn->offset);
2189
2190 state.df = true;
2191 break;
2192
2193 case INSN_CLD:
2194 if (!state.df && insn->func)
2195 WARN_FUNC("redundant CLD", sec, insn->offset);
2196
2197 state.df = false;
2198 break;
2199
2175 default: 2200 default:
2176 break; 2201 break;
2177 } 2202 }
diff --git a/tools/objtool/check.h b/tools/objtool/check.h
index 78a95d06c165..71e54f97dbcd 100644
--- a/tools/objtool/check.h
+++ b/tools/objtool/check.h
@@ -31,7 +31,7 @@ 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, uaccess; 34 bool drap, end, uaccess, df;
35 unsigned int uaccess_stack; 35 unsigned int uaccess_stack;
36 int drap_reg, drap_offset; 36 int drap_reg, drap_offset;
37 struct cfi_reg vals[CFI_NUM_REGS]; 37 struct cfi_reg vals[CFI_NUM_REGS];