summaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/kprobes
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-08-30 19:10:31 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2023-08-30 19:10:31 +0200
commit87fa732dc5ff9ea6a2e75b630f7931899e845eb1 (patch)
treee6a5e9223b3c45daa8179d859feb6234ab060055 /arch/x86/kernel/kprobes
parentMerge tag 'x86_mm_for_6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/g... (diff)
parentx86/kprobes: Prohibit probing on compiler generated CFI checking code (diff)
downloadlinux-87fa732dc5ff9ea6a2e75b630f7931899e845eb1.tar.xz
linux-87fa732dc5ff9ea6a2e75b630f7931899e845eb1.zip
Merge tag 'x86-core-2023-08-30-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 core updates from Thomas Gleixner: - Prevent kprobes on compiler generated CFI checking code. The compiler generates an instruction sequence for indirect call checks. If this sequence is modified with a kprobe, then the check fails. So the instructions must be protected against probing. - A few minor cleanups for the SMP code * tag 'x86-core-2023-08-30-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/kprobes: Prohibit probing on compiler generated CFI checking code x86/smpboot: Change smp_store_boot_cpu_info() to static x86/smp: Remove a non-existent function declaration x86/smpboot: Remove a stray comment about CPU hotplug
Diffstat (limited to 'arch/x86/kernel/kprobes')
-rw-r--r--arch/x86/kernel/kprobes/core.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c
index f7f6042eb7e6..e8babebad7b8 100644
--- a/arch/x86/kernel/kprobes/core.c
+++ b/arch/x86/kernel/kprobes/core.c
@@ -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);
}