summaryrefslogtreecommitdiffstats
path: root/tools/objtool
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2019-02-25 11:10:55 +0100
committerIngo Molnar <mingo@kernel.org>2019-04-03 11:02:24 +0200
commit2f0f9e9ad7b3459c5c54ef2c03145a98e65dd158 (patch)
tree6ce2229a931e53504851d1e98b6319630ff952c7 /tools/objtool
parentea24213d8088f9da73e1b6aadf7abd2435b70397 (diff)
downloadlinux-2f0f9e9ad7b3459c5c54ef2c03145a98e65dd158.tar.bz2
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>
Diffstat (limited to 'tools/objtool')
-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 @@
#define INSN_NOP 10
#define INSN_STAC 11
#define INSN_CLAC 12
-#define INSN_OTHER 13
+#define INSN_STD 13
+#define INSN_CLD 14
+#define INSN_OTHER 15
#define INSN_LAST INSN_OTHER
enum 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,
*type = INSN_CALL;
break;
+ case 0xfc:
+ *type = INSN_CLD;
+ break;
+
+ case 0xfd:
+ *type = INSN_STD;
+ break;
+
case 0xff:
if (modrm_reg == 2 || modrm_reg == 3)
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)
return 1;
}
+ if (state->df) {
+ WARN_FUNC("call to %s() with DF set",
+ insn->sec, insn->offset, insn_dest_name(insn));
+ return 1;
+ }
+
return 0;
}
@@ -2044,6 +2050,11 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
return 1;
}
+ if (state.df) {
+ WARN_FUNC("return with DF set", sec, insn->offset);
+ return 1;
+ }
+
if (func && has_modified_stack_frame(&state)) {
WARN_FUNC("return with modified stack frame",
sec, insn->offset);
@@ -2172,6 +2183,20 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
state.uaccess = false;
break;
+ case INSN_STD:
+ if (state.df)
+ WARN_FUNC("recursive STD", sec, insn->offset);
+
+ state.df = true;
+ break;
+
+ case INSN_CLD:
+ if (!state.df && insn->func)
+ WARN_FUNC("redundant CLD", sec, insn->offset);
+
+ state.df = false;
+ break;
+
default:
break;
}
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 {
int stack_size;
unsigned char type;
bool bp_scratch;
- bool drap, end, uaccess;
+ bool drap, end, uaccess, df;
unsigned int uaccess_stack;
int drap_reg, drap_offset;
struct cfi_reg vals[CFI_NUM_REGS];