]> www.infradead.org Git - users/hch/misc.git/commitdiff
objtool: Split INSN_CONTEXT_SWITCH into INSN_SYSCALL and INSN_SYSRET
authorJosh Poimboeuf <jpoimboe@kernel.org>
Tue, 8 Apr 2025 07:02:14 +0000 (00:02 -0700)
committerIngo Molnar <mingo@kernel.org>
Tue, 8 Apr 2025 07:14:11 +0000 (09:14 +0200)
INSN_CONTEXT_SWITCH is ambiguous.  It can represent both call semantics
(SYSCALL, SYSENTER) and return semantics (SYSRET, IRET, RETS, RETU).
Those differ significantly: calls preserve control flow whereas returns
terminate it.

Objtool uses an arbitrary rule for INSN_CONTEXT_SWITCH that almost works
by accident: if in a function, keep going; otherwise stop.  It should
instead be based on the semantics of the underlying instruction.

In preparation for improving that, split INSN_CONTEXT_SWITCH into
INSN_SYCALL and INSN_SYSRET.

No functional change.

Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: https://lore.kernel.org/r/19a76c74d2c051d3bc9a775823cafc65ad267a7a.1744095216.git.jpoimboe@kernel.org
tools/objtool/arch/x86/decode.c
tools/objtool/check.c
tools/objtool/include/objtool/arch.h

index 33d861c04ebd8ff37ef69b66f2c601755f0ad077..3ce7b54003c229a1c300584f550be072640cb488 100644 (file)
@@ -522,7 +522,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
                        case INAT_PFX_REPNE:
                                if (modrm == 0xca)
                                        /* eretu/erets */
-                                       insn->type = INSN_CONTEXT_SWITCH;
+                                       insn->type = INSN_SYSRET;
                                break;
                        default:
                                if (modrm == 0xca)
@@ -535,11 +535,15 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
 
                        insn->type = INSN_JUMP_CONDITIONAL;
 
-               } else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 ||
-                          op2 == 0x35) {
+               } else if (op2 == 0x05 || op2 == 0x34) {
 
-                       /* sysenter, sysret */
-                       insn->type = INSN_CONTEXT_SWITCH;
+                       /* syscall, sysenter */
+                       insn->type = INSN_SYSCALL;
+
+               } else if (op2 == 0x07 || op2 == 0x35) {
+
+                       /* sysret, sysexit */
+                       insn->type = INSN_SYSRET;
 
                } else if (op2 == 0x0b || op2 == 0xb9) {
 
@@ -676,7 +680,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
 
        case 0xca: /* retf */
        case 0xcb: /* retf */
-               insn->type = INSN_CONTEXT_SWITCH;
+               insn->type = INSN_SYSRET;
                break;
 
        case 0xe0: /* loopne */
@@ -721,7 +725,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
                } else if (modrm_reg == 5) {
 
                        /* jmpf */
-                       insn->type = INSN_CONTEXT_SWITCH;
+                       insn->type = INSN_SYSRET;
 
                } else if (modrm_reg == 6) {
 
index c81b070ca4952f38b9c4a8ab2b7e2ffb9ab02329..2c703b960420a456cce45acfa33ef3298c62fae2 100644 (file)
@@ -3684,7 +3684,8 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
 
                        break;
 
-               case INSN_CONTEXT_SWITCH:
+               case INSN_SYSCALL:
+               case INSN_SYSRET:
                        if (func) {
                                if (!next_insn || !next_insn->hint) {
                                        WARN_INSN(insn, "unsupported instruction in callable function");
@@ -3886,7 +3887,8 @@ static int validate_unret(struct objtool_file *file, struct instruction *insn)
                        WARN_INSN(insn, "RET before UNTRAIN");
                        return 1;
 
-               case INSN_CONTEXT_SWITCH:
+               case INSN_SYSCALL:
+               case INSN_SYSRET:
                        if (insn_func(insn))
                                break;
                        return 0;
index 089a1acc48a8d04d0523b852e698a002c39ca8b2..01ef6f415adf64995dfb6ac48dcc00026a116b18 100644 (file)
@@ -19,7 +19,8 @@ enum insn_type {
        INSN_CALL,
        INSN_CALL_DYNAMIC,
        INSN_RETURN,
-       INSN_CONTEXT_SWITCH,
+       INSN_SYSCALL,
+       INSN_SYSRET,
        INSN_BUG,
        INSN_NOP,
        INSN_STAC,