Skip to content

Commit 7d209d1

Browse files
author
Peter Zijlstra
committed
objtool: Add IBT/ENDBR decoding
Intel IBT requires the target of any indirect CALL or JMP instruction to be the ENDBR instruction; optionally it allows those two instructions to have a NOTRACK prefix in order to avoid this requirement. The kernel will not enable the use of NOTRACK, as such any occurence of it in compiler generated code should be flagged. Teach objtool to Decode ENDBR instructions and WARN about NOTRACK prefixes. Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Acked-by: Josh Poimboeuf <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 96db4a9 commit 7d209d1

File tree

2 files changed

+30
-5
lines changed

2 files changed

+30
-5
lines changed

tools/objtool/arch/x86/decode.c

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,18 @@ unsigned long arch_jump_destination(struct instruction *insn)
103103
#define rm_is_mem(reg) (mod_is_mem() && !is_RIP() && rm_is(reg))
104104
#define rm_is_reg(reg) (mod_is_reg() && modrm_rm == (reg))
105105

106+
static bool has_notrack_prefix(struct insn *insn)
107+
{
108+
int i;
109+
110+
for (i = 0; i < insn->prefixes.nbytes; i++) {
111+
if (insn->prefixes.bytes[i] == 0x3e)
112+
return true;
113+
}
114+
115+
return false;
116+
}
117+
106118
int arch_decode_instruction(struct objtool_file *file, const struct section *sec,
107119
unsigned long offset, unsigned int maxlen,
108120
unsigned int *len, enum insn_type *type,
@@ -112,7 +124,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
112124
const struct elf *elf = file->elf;
113125
struct insn insn;
114126
int x86_64, ret;
115-
unsigned char op1, op2, op3,
127+
unsigned char op1, op2, op3, prefix,
116128
rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, rex_x = 0,
117129
modrm = 0, modrm_mod = 0, modrm_rm = 0, modrm_reg = 0,
118130
sib = 0, /* sib_scale = 0, */ sib_index = 0, sib_base = 0;
@@ -137,6 +149,8 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
137149
if (insn.vex_prefix.nbytes)
138150
return 0;
139151

152+
prefix = insn.prefixes.bytes[0];
153+
140154
op1 = insn.opcode.bytes[0];
141155
op2 = insn.opcode.bytes[1];
142156
op3 = insn.opcode.bytes[2];
@@ -492,6 +506,12 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
492506
/* nopl/nopw */
493507
*type = INSN_NOP;
494508

509+
} else if (op2 == 0x1e) {
510+
511+
if (prefix == 0xf3 && (modrm == 0xfa || modrm == 0xfb))
512+
*type = INSN_ENDBR;
513+
514+
495515
} else if (op2 == 0x38 && op3 == 0xf8) {
496516
if (insn.prefixes.nbytes == 1 &&
497517
insn.prefixes.bytes[0] == 0xf2) {
@@ -636,20 +656,24 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
636656
break;
637657

638658
case 0xff:
639-
if (modrm_reg == 2 || modrm_reg == 3)
659+
if (modrm_reg == 2 || modrm_reg == 3) {
640660

641661
*type = INSN_CALL_DYNAMIC;
662+
if (has_notrack_prefix(&insn))
663+
WARN("notrack prefix found at %s:0x%lx", sec->name, offset);
642664

643-
else if (modrm_reg == 4)
665+
} else if (modrm_reg == 4) {
644666

645667
*type = INSN_JUMP_DYNAMIC;
668+
if (has_notrack_prefix(&insn))
669+
WARN("notrack prefix found at %s:0x%lx", sec->name, offset);
646670

647-
else if (modrm_reg == 5)
671+
} else if (modrm_reg == 5) {
648672

649673
/* jmpf */
650674
*type = INSN_CONTEXT_SWITCH;
651675

652-
else if (modrm_reg == 6) {
676+
} else if (modrm_reg == 6) {
653677

654678
/* push from mem */
655679
ADD_OP(op) {

tools/objtool/include/objtool/arch.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ enum insn_type {
2727
INSN_STD,
2828
INSN_CLD,
2929
INSN_TRAP,
30+
INSN_ENDBR,
3031
INSN_OTHER,
3132
};
3233

0 commit comments

Comments
 (0)