Skip to content

Commit 9831c62

Browse files
author
Peter Zijlstra
committed
x86/cfi: Extend ENDBR sealing to kCFI
Kees noted that IBT sealing could be extended to kCFI. Fundamentally it is the list of functions that do not have their address taken and are thus never called indirectly. It doesn't matter that objtool uses IBT infrastructure to determine this list, once we have it it can also be used to clobber kCFI hashes and avoid kCFI indirect calls. Suggested-by: Kees Cook <keescook@chromium.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Kees Cook <keescook@chromium.org> Reviewed-by: Sami Tolvanen <samitolvanen@google.com> Link: https://lkml.kernel.org/r/20230622144321.494426891%40infradead.org
1 parent be0fffa commit 9831c62

File tree

1 file changed

+43
-1
lines changed

1 file changed

+43
-1
lines changed

arch/x86/kernel/alternative.c

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,8 @@ void __init_or_module noinline apply_returns(s32 *start, s32 *end) { }
778778

779779
#ifdef CONFIG_X86_KERNEL_IBT
780780

781+
static void poison_cfi(void *addr);
782+
781783
static void __init_or_module poison_endbr(void *addr, bool warn)
782784
{
783785
u32 endbr, poison = gen_endbr_poison();
@@ -802,6 +804,9 @@ static void __init_or_module poison_endbr(void *addr, bool warn)
802804

803805
/*
804806
* Generated by: objtool --ibt
807+
*
808+
* Seal the functions for indirect calls by clobbering the ENDBR instructions
809+
* and the kCFI hash value.
805810
*/
806811
void __init_or_module noinline apply_seal_endbr(s32 *start, s32 *end)
807812
{
@@ -812,7 +817,7 @@ void __init_or_module noinline apply_seal_endbr(s32 *start, s32 *end)
812817

813818
poison_endbr(addr, true);
814819
if (IS_ENABLED(CONFIG_FINEIBT))
815-
poison_endbr(addr - 16, false);
820+
poison_cfi(addr - 16);
816821
}
817822
}
818823

@@ -1177,13 +1182,50 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
11771182
pr_err("Something went horribly wrong trying to rewrite the CFI implementation.\n");
11781183
}
11791184

1185+
static inline void poison_hash(void *addr)
1186+
{
1187+
*(u32 *)addr = 0;
1188+
}
1189+
1190+
static void poison_cfi(void *addr)
1191+
{
1192+
switch (cfi_mode) {
1193+
case CFI_FINEIBT:
1194+
/*
1195+
* __cfi_\func:
1196+
* osp nopl (%rax)
1197+
* subl $0, %r10d
1198+
* jz 1f
1199+
* ud2
1200+
* 1: nop
1201+
*/
1202+
poison_endbr(addr, false);
1203+
poison_hash(addr + fineibt_preamble_hash);
1204+
break;
1205+
1206+
case CFI_KCFI:
1207+
/*
1208+
* __cfi_\func:
1209+
* movl $0, %eax
1210+
* .skip 11, 0x90
1211+
*/
1212+
poison_hash(addr + 1);
1213+
break;
1214+
1215+
default:
1216+
break;
1217+
}
1218+
}
1219+
11801220
#else
11811221

11821222
static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
11831223
s32 *start_cfi, s32 *end_cfi, bool builtin)
11841224
{
11851225
}
11861226

1227+
static void poison_cfi(void *addr) { }
1228+
11871229
#endif
11881230

11891231
void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,

0 commit comments

Comments
 (0)