[PATCH 20/20] objtool: Add Direction Flag validation

From: Peter Zijlstra
Date: Thu Mar 07 2019 - 06:53:47 EST


Having DF escape is BAD(tm).

Suggested-by: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
Signed-off-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx>
---
tools/objtool/arch.h | 4 +++-
tools/objtool/arch/x86/decode.c | 8 ++++++++
tools/objtool/check.c | 25 +++++++++++++++++++++++++
tools/objtool/check.h | 2 +-
4 files changed, 37 insertions(+), 2 deletions(-)

--- 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 {
--- a/tools/objtool/arch/x86/decode.c
+++ b/tools/objtool/arch/x86/decode.c
@@ -456,6 +456,14 @@ int arch_decode_instruction(struct elf *
*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)

--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -2020,6 +2020,11 @@ static int validate_branch(struct objtoo
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);
@@ -2043,6 +2048,12 @@ static int validate_branch(struct objtoo
return 1;
}

+ if (state.df) {
+ WARN_FUNC("call to %s() with DF set",
+ sec, insn->offset, insn_dest_name(insn));
+ return 1;
+ }
+
if (insn->type == INSN_JUMP_UNCONDITIONAL ||
insn->type == INSN_JUMP_DYNAMIC)
return 0;
@@ -2160,6 +2171,20 @@ static int validate_branch(struct objtoo
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;
}
--- 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];