Add PUSHF / POPF state.uaccess restore logic. This makes
user_access_save() / user_access_restore() 'work' with objtool.

XXX: should be merged with the previous patch such that KASAN
doesn't explode in between. Split for review.

Signed-off-by: Peter Zijlstra (Intel) <pet...@infradead.org>
---
 tools/objtool/arch.h            |    2 ++
 tools/objtool/arch/x86/decode.c |    4 ++--
 tools/objtool/check.c           |   30 ++++++++++++++++++++++++++----
 tools/objtool/check.h           |    1 +
 4 files changed, 31 insertions(+), 6 deletions(-)

--- a/tools/objtool/arch.h
+++ b/tools/objtool/arch.h
@@ -43,6 +43,7 @@ enum op_dest_type {
        OP_DEST_REG_INDIRECT,
        OP_DEST_MEM,
        OP_DEST_PUSH,
+       OP_DEST_PUSHF,
        OP_DEST_LEAVE,
 };
 
@@ -57,6 +58,7 @@ enum op_src_type {
        OP_SRC_REG_INDIRECT,
        OP_SRC_CONST,
        OP_SRC_POP,
+       OP_SRC_POPF,
        OP_SRC_ADD,
        OP_SRC_AND,
 };
--- a/tools/objtool/arch/x86/decode.c
+++ b/tools/objtool/arch/x86/decode.c
@@ -357,13 +357,13 @@ int arch_decode_instruction(struct elf *
                /* pushf */
                *type = INSN_STACK;
                op->src.type = OP_SRC_CONST;
-               op->dest.type = OP_DEST_PUSH;
+               op->dest.type = OP_DEST_PUSHF;
                break;
 
        case 0x9d:
                /* popf */
                *type = INSN_STACK;
-               op->src.type = OP_SRC_POP;
+               op->src.type = OP_SRC_POPF;
                op->dest.type = OP_DEST_MEM;
                break;
 
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1392,11 +1392,11 @@ static int update_insn_state_regs(struct
                return 0;
 
        /* push */
-       if (op->dest.type == OP_DEST_PUSH)
+       if (op->dest.type == OP_DEST_PUSH || op->dest.type == OP_DEST_PUSHF)
                cfa->offset += 8;
 
        /* pop */
-       if (op->src.type == OP_SRC_POP)
+       if (op->src.type == OP_SRC_POP || op->src.type == OP_SRC_POPF)
                cfa->offset -= 8;
 
        /* add immediate to sp */
@@ -1653,6 +1653,7 @@ static int update_insn_state(struct inst
                        break;
 
                case OP_SRC_POP:
+               case OP_SRC_POPF:
                        if (!state->drap && op->dest.type == OP_DEST_REG &&
                            op->dest.reg == cfa->base) {
 
@@ -1717,6 +1718,7 @@ static int update_insn_state(struct inst
                break;
 
        case OP_DEST_PUSH:
+       case OP_DEST_PUSHF:
                state->stack_size += 8;
                if (cfa->base == CFI_SP)
                        cfa->offset += 8;
@@ -1807,7 +1809,7 @@ static int update_insn_state(struct inst
                break;
 
        case OP_DEST_MEM:
-               if (op->src.type != OP_SRC_POP) {
+               if (op->src.type != OP_SRC_POP && op->src.type != OP_SRC_POPF) {
                        WARN_FUNC("unknown stack-related memory operation",
                                  insn->sec, insn->offset);
                        return -1;
@@ -2109,6 +2111,26 @@ static int validate_branch(struct objtoo
                        if (update_insn_state(insn, &state))
                                return 1;
 
+                       if (insn->stack_op.dest.type == OP_DEST_PUSHF) {
+                               if (!state.uaccess_stack) {
+                                       state.uaccess_stack = 1;
+                               } else if (state.uaccess_stack >> 31) {
+                                       WARN_FUNC("PUSHF stack exhausted", sec, 
insn->offset);
+                                       return 1;
+                               }
+                               state.uaccess_stack <<= 1;
+                               state.uaccess_stack  |= state.uaccess;
+                       }
+
+                       if (insn->stack_op.src.type == OP_SRC_POPF) {
+                               if (state.uaccess_stack) {
+                                       state.uaccess = state.uaccess_stack & 1;
+                                       state.uaccess_stack >>= 1;
+                                       if (state.uaccess_stack == 1)
+                                               state.uaccess_stack = 0;
+                               }
+                       }
+
                        break;
 
                case INSN_STAC:
@@ -2126,7 +2148,7 @@ static int validate_branch(struct objtoo
                                return 1;
                        }
 
-                       if (func_uaccess_safe(func)) {
+                       if (func_uaccess_safe(func) && !state.uaccess_stack) {
                                WARN_FUNC("UACCESS-safe disables UACCESS", sec, 
insn->offset);
                                return 1;
                        }
--- a/tools/objtool/check.h
+++ b/tools/objtool/check.h
@@ -32,6 +32,7 @@ struct insn_state {
        unsigned char type;
        bool bp_scratch;
        bool drap, end, uaccess;
+       unsigned int uaccess_stack;
        int drap_reg, drap_offset;
        struct cfi_reg vals[CFI_NUM_REGS];
 };


Reply via email to