Skip to content

Commit ed1cb76

Browse files
committed
objtool: Detect non-relocated text references
When kernel IBT is enabled, objtool detects all text references in order to determine which functions can be indirectly branched to. In text, such references look like one of the following: mov $0x0,%rax R_X86_64_32S .init.text+0x7e0a0 lea 0x0(%rip),%rax R_X86_64_PC32 autoremove_wake_function-0x4 Either way the function pointer is denoted by a relocation, so objtool just reads that. However there are some "lea xxx(%rip)" cases which don't use relocations because they're referencing code in the same translation unit. Objtool doesn't have visibility to those. The only currently known instances of that are a few hand-coded asm text references which don't actually need ENDBR. So it's not actually a problem at the moment. However if we enable -fpie, the compiler would start generating them and there would definitely be bugs in the IBT sealing. Detect non-relocated text references and handle them appropriately. [ Note: I removed the manual static_call_tramp check -- that should already be handled by the noendbr check. ] Reported-by: Ard Biesheuvel <[email protected]> Tested-by: Ard Biesheuvel <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Josh Poimboeuf <[email protected]>
1 parent 8e929cb commit ed1cb76

File tree

5 files changed

+77
-53
lines changed

5 files changed

+77
-53
lines changed

arch/x86/kernel/acpi/wakeup_64.S

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ SYM_FUNC_START(do_suspend_lowlevel)
8787

8888
.align 4
8989
.Lresume_point:
90+
ANNOTATE_NOENDBR
9091
/* We don't restore %rax, it must be 0 anyway */
9192
movq $saved_context, %rax
9293
movq saved_context_cr4(%rax), %rbx

arch/x86/kernel/head_64.S

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ SYM_CODE_START_NOALIGN(startup_64)
7777
lretq
7878

7979
.Lon_kernel_cs:
80+
ANNOTATE_NOENDBR
8081
UNWIND_HINT_END_OF_STACK
8182

8283
#ifdef CONFIG_AMD_MEM_ENCRYPT

tools/objtool/arch/x86/decode.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -456,17 +456,19 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
456456
if (!rex_w)
457457
break;
458458

459-
/* skip RIP relative displacement */
460-
if (is_RIP())
461-
break;
462-
463459
/* skip nontrivial SIB */
464460
if (have_SIB()) {
465461
modrm_rm = sib_base;
466462
if (sib_index != CFI_SP)
467463
break;
468464
}
469465

466+
/* lea disp(%rip), %dst */
467+
if (is_RIP()) {
468+
insn->type = INSN_LEA_RIP;
469+
break;
470+
}
471+
470472
/* lea disp(%src), %dst */
471473
ADD_OP(op) {
472474
op->src.offset = ins.displacement.value;
@@ -737,7 +739,10 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
737739
break;
738740
}
739741

740-
insn->immediate = ins.immediate.nbytes ? ins.immediate.value : 0;
742+
if (ins.immediate.nbytes)
743+
insn->immediate = ins.immediate.value;
744+
else if (ins.displacement.nbytes)
745+
insn->immediate = ins.displacement.value;
741746

742747
return 0;
743748
}

tools/objtool/check.c

Lines changed: 64 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4392,6 +4392,51 @@ static bool noendbr_range(struct objtool_file *file, struct instruction *insn)
43924392
return insn->offset == sym->offset + sym->len;
43934393
}
43944394

4395+
static int __validate_ibt_insn(struct objtool_file *file, struct instruction *insn,
4396+
struct instruction *dest)
4397+
{
4398+
if (dest->type == INSN_ENDBR) {
4399+
mark_endbr_used(dest);
4400+
return 0;
4401+
}
4402+
4403+
if (insn_func(dest) && insn_func(insn) &&
4404+
insn_func(dest)->pfunc == insn_func(insn)->pfunc) {
4405+
/*
4406+
* Anything from->to self is either _THIS_IP_ or
4407+
* IRET-to-self.
4408+
*
4409+
* There is no sane way to annotate _THIS_IP_ since the
4410+
* compiler treats the relocation as a constant and is
4411+
* happy to fold in offsets, skewing any annotation we
4412+
* do, leading to vast amounts of false-positives.
4413+
*
4414+
* There's also compiler generated _THIS_IP_ through
4415+
* KCOV and such which we have no hope of annotating.
4416+
*
4417+
* As such, blanket accept self-references without
4418+
* issue.
4419+
*/
4420+
return 0;
4421+
}
4422+
4423+
/*
4424+
* Accept anything ANNOTATE_NOENDBR.
4425+
*/
4426+
if (dest->noendbr)
4427+
return 0;
4428+
4429+
/*
4430+
* Accept if this is the instruction after a symbol
4431+
* that is (no)endbr -- typical code-range usage.
4432+
*/
4433+
if (noendbr_range(file, dest))
4434+
return 0;
4435+
4436+
WARN_INSN(insn, "relocation to !ENDBR: %s", offstr(dest->sec, dest->offset));
4437+
return 1;
4438+
}
4439+
43954440
static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn)
43964441
{
43974442
struct instruction *dest;
@@ -4404,6 +4449,7 @@ static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn
44044449
* direct/indirect branches:
44054450
*/
44064451
switch (insn->type) {
4452+
44074453
case INSN_CALL:
44084454
case INSN_CALL_DYNAMIC:
44094455
case INSN_JUMP_CONDITIONAL:
@@ -4413,6 +4459,23 @@ static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn
44134459
case INSN_RETURN:
44144460
case INSN_NOP:
44154461
return 0;
4462+
4463+
case INSN_LEA_RIP:
4464+
if (!insn_reloc(file, insn)) {
4465+
/* local function pointer reference without reloc */
4466+
4467+
off = arch_jump_destination(insn);
4468+
4469+
dest = find_insn(file, insn->sec, off);
4470+
if (!dest) {
4471+
WARN_INSN(insn, "corrupt function pointer reference");
4472+
return 1;
4473+
}
4474+
4475+
return __validate_ibt_insn(file, insn, dest);
4476+
}
4477+
break;
4478+
44164479
default:
44174480
break;
44184481
}
@@ -4423,13 +4486,6 @@ static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn
44234486
reloc_offset(reloc) + 1,
44244487
(insn->offset + insn->len) - (reloc_offset(reloc) + 1))) {
44254488

4426-
/*
4427-
* static_call_update() references the trampoline, which
4428-
* doesn't have (or need) ENDBR. Skip warning in that case.
4429-
*/
4430-
if (reloc->sym->static_call_tramp)
4431-
continue;
4432-
44334489
off = reloc->sym->offset;
44344490
if (reloc_type(reloc) == R_X86_64_PC32 ||
44354491
reloc_type(reloc) == R_X86_64_PLT32)
@@ -4441,47 +4497,7 @@ static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn
44414497
if (!dest)
44424498
continue;
44434499

4444-
if (dest->type == INSN_ENDBR) {
4445-
mark_endbr_used(dest);
4446-
continue;
4447-
}
4448-
4449-
if (insn_func(dest) && insn_func(insn) &&
4450-
insn_func(dest)->pfunc == insn_func(insn)->pfunc) {
4451-
/*
4452-
* Anything from->to self is either _THIS_IP_ or
4453-
* IRET-to-self.
4454-
*
4455-
* There is no sane way to annotate _THIS_IP_ since the
4456-
* compiler treats the relocation as a constant and is
4457-
* happy to fold in offsets, skewing any annotation we
4458-
* do, leading to vast amounts of false-positives.
4459-
*
4460-
* There's also compiler generated _THIS_IP_ through
4461-
* KCOV and such which we have no hope of annotating.
4462-
*
4463-
* As such, blanket accept self-references without
4464-
* issue.
4465-
*/
4466-
continue;
4467-
}
4468-
4469-
/*
4470-
* Accept anything ANNOTATE_NOENDBR.
4471-
*/
4472-
if (dest->noendbr)
4473-
continue;
4474-
4475-
/*
4476-
* Accept if this is the instruction after a symbol
4477-
* that is (no)endbr -- typical code-range usage.
4478-
*/
4479-
if (noendbr_range(file, dest))
4480-
continue;
4481-
4482-
WARN_INSN(insn, "relocation to !ENDBR: %s", offstr(dest->sec, dest->offset));
4483-
4484-
warnings++;
4500+
warnings += __validate_ibt_insn(file, insn, dest);
44854501
}
44864502

44874503
return warnings;

tools/objtool/include/objtool/arch.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ enum insn_type {
2828
INSN_CLD,
2929
INSN_TRAP,
3030
INSN_ENDBR,
31+
INSN_LEA_RIP,
3132
INSN_OTHER,
3233
};
3334

0 commit comments

Comments
 (0)