mirror of
https://github.com/lkl/linux.git
synced 2025-12-18 23:53:03 +09:00
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
This commit is contained in:
committed by
Peter Zijlstra
parent
d7114f83ee
commit
b65413768a
@@ -45,6 +45,7 @@
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/pgtable.h>
|
||||
#include <linux/set_memory.h>
|
||||
#include <linux/cfi.h>
|
||||
|
||||
#include <asm/text-patching.h>
|
||||
#include <asm/cacheflush.h>
|
||||
@@ -293,7 +294,40 @@ static int can_probe(unsigned long paddr)
|
||||
#endif
|
||||
addr += insn.length;
|
||||
}
|
||||
if (IS_ENABLED(CONFIG_CFI_CLANG)) {
|
||||
/*
|
||||
* The compiler generates the following instruction sequence
|
||||
* for indirect call checks and cfi.c decodes this;
|
||||
*
|
||||
* movl -<id>, %r10d ; 6 bytes
|
||||
* addl -4(%reg), %r10d ; 4 bytes
|
||||
* je .Ltmp1 ; 2 bytes
|
||||
* ud2 ; <- regs->ip
|
||||
* .Ltmp1:
|
||||
*
|
||||
* Also, these movl and addl are used for showing expected
|
||||
* type. So those must not be touched.
|
||||
*/
|
||||
__addr = recover_probed_instruction(buf, addr);
|
||||
if (!__addr)
|
||||
return 0;
|
||||
|
||||
if (insn_decode_kernel(&insn, (void *)__addr) < 0)
|
||||
return 0;
|
||||
|
||||
if (insn.opcode.value == 0xBA)
|
||||
offset = 12;
|
||||
else if (insn.opcode.value == 0x3)
|
||||
offset = 6;
|
||||
else
|
||||
goto out;
|
||||
|
||||
/* This movl/addl is used for decoding CFI. */
|
||||
if (is_cfi_trap(addr + offset))
|
||||
return 0;
|
||||
}
|
||||
|
||||
out:
|
||||
return (addr == paddr);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,11 +19,13 @@ static inline enum bug_trap_type report_cfi_failure_noaddr(struct pt_regs *regs,
|
||||
{
|
||||
return report_cfi_failure(regs, addr, NULL, 0);
|
||||
}
|
||||
#endif /* CONFIG_CFI_CLANG */
|
||||
|
||||
#ifdef CONFIG_ARCH_USES_CFI_TRAPS
|
||||
bool is_cfi_trap(unsigned long addr);
|
||||
#else
|
||||
static inline bool is_cfi_trap(unsigned long addr) { return false; }
|
||||
#endif
|
||||
#endif /* CONFIG_CFI_CLANG */
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
#ifdef CONFIG_ARCH_USES_CFI_TRAPS
|
||||
|
||||
Reference in New Issue
Block a user