]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
objtool: Add Direction Flag validation
authorPeter Zijlstra <peterz@infradead.org>
Mon, 25 Feb 2019 10:10:55 +0000 (11:10 +0100)
committerIngo Molnar <mingo@kernel.org>
Wed, 3 Apr 2019 09:02:24 +0000 (11:02 +0200)
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>
tools/objtool/arch.h
tools/objtool/arch/x86/decode.c
tools/objtool/check.c
tools/objtool/check.h

index 467c2fe798a9ea5c0e1666cf3d74ae17eafabc8a..7a111a77b7aa418cb2c50edaf62a470150f7f888 100644 (file)
@@ -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 {
index ab20a96fee50d01aaf6252892de65d1c44deefe6..472e991f6512d26bcfd81e660fc8f6244a3eb24e 100644 (file)
@@ -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)
 
index 965e954e07f43c7c293ad5e7b54dea69f0d28148..38b0517dc49efa3a0cd5dfaea5d3cdf0d7550355 100644 (file)
@@ -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;
                }
index 78a95d06c165eee1b985cb165742075389de4316..71e54f97dbcdca023668178dbfb6cd71acc75cc5 100644 (file)
@@ -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];