Skip to content

Commit b654137

Browse files
mhiramatPeter Zijlstra
authored andcommitted
x86/kprobes: Prohibit probing on compiler generated CFI checking code
Prohibit probing on the compiler generated CFI typeid checking code because it is used for decoding typeid when CFI error happens. The compiler generates the following instruction sequence for indirect call checks on x86;   movl -<id>, %r10d ; 6 bytes addl -4(%reg), %r10d ; 4 bytes je .Ltmp1 ; 2 bytes ud2 ; <- regs->ip And handle_cfi_failure() decodes these instructions (movl and addl) for the typeid and the target address. Thus if we put a kprobe on those instructions, the decode will fail and report a wrong typeid and target address. Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/168904025785.116016.12766408611437534723.stgit@devnote2
1 parent d7114f8 commit b654137

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

arch/x86/kernel/kprobes/core.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include <linux/vmalloc.h>
4646
#include <linux/pgtable.h>
4747
#include <linux/set_memory.h>
48+
#include <linux/cfi.h>
4849

4950
#include <asm/text-patching.h>
5051
#include <asm/cacheflush.h>
@@ -293,7 +294,40 @@ static int can_probe(unsigned long paddr)
293294
#endif
294295
addr += insn.length;
295296
}
297+
if (IS_ENABLED(CONFIG_CFI_CLANG)) {
298+
/*
299+
* The compiler generates the following instruction sequence
300+
* for indirect call checks and cfi.c decodes this;
301+
*
302+
*  movl -<id>, %r10d ; 6 bytes
303+
* addl -4(%reg), %r10d ; 4 bytes
304+
* je .Ltmp1 ; 2 bytes
305+
* ud2 ; <- regs->ip
306+
* .Ltmp1:
307+
*
308+
* Also, these movl and addl are used for showing expected
309+
* type. So those must not be touched.
310+
*/
311+
__addr = recover_probed_instruction(buf, addr);
312+
if (!__addr)
313+
return 0;
314+
315+
if (insn_decode_kernel(&insn, (void *)__addr) < 0)
316+
return 0;
317+
318+
if (insn.opcode.value == 0xBA)
319+
offset = 12;
320+
else if (insn.opcode.value == 0x3)
321+
offset = 6;
322+
else
323+
goto out;
324+
325+
/* This movl/addl is used for decoding CFI. */
326+
if (is_cfi_trap(addr + offset))
327+
return 0;
328+
}
296329

330+
out:
297331
return (addr == paddr);
298332
}
299333

include/linux/cfi.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ static inline enum bug_trap_type report_cfi_failure_noaddr(struct pt_regs *regs,
1919
{
2020
return report_cfi_failure(regs, addr, NULL, 0);
2121
}
22+
#endif /* CONFIG_CFI_CLANG */
2223

2324
#ifdef CONFIG_ARCH_USES_CFI_TRAPS
2425
bool is_cfi_trap(unsigned long addr);
26+
#else
27+
static inline bool is_cfi_trap(unsigned long addr) { return false; }
2528
#endif
26-
#endif /* CONFIG_CFI_CLANG */
2729

2830
#ifdef CONFIG_MODULES
2931
#ifdef CONFIG_ARCH_USES_CFI_TRAPS

0 commit comments

Comments
 (0)