All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sami Tolvanen <samitolvanen@google.com>
To: linux-kernel@vger.kernel.org
Cc: Kees Cook <keescook@chromium.org>,
	Josh Poimboeuf <jpoimboe@redhat.com>,
	Peter Zijlstra <peterz@infradead.org>,
	x86@kernel.org, Catalin Marinas <catalin.marinas@arm.com>,
	Will Deacon <will@kernel.org>,
	Mark Rutland <mark.rutland@arm.com>,
	Nathan Chancellor <nathan@kernel.org>,
	Nick Desaulniers <ndesaulniers@google.com>,
	Joao Moreira <joao@overdrivepizza.com>,
	Sedat Dilek <sedat.dilek@gmail.com>,
	Steven Rostedt <rostedt@goodmis.org>,
	linux-hardening@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, llvm@lists.linux.dev,
	Sami Tolvanen <samitolvanen@google.com>
Subject: [RFC PATCH v3 20/20] x86: Add support for CONFIG_CFI_CLANG
Date: Fri, 10 Jun 2022 16:35:13 -0700	[thread overview]
Message-ID: <20220610233513.1798771-21-samitolvanen@google.com> (raw)
In-Reply-To: <20220610233513.1798771-1-samitolvanen@google.com>

With CONFIG_CFI_CLANG, the compiler injects a type preamble immediately
before each function and a check to validate the target function type
before indirect calls:

  ; type preamble
  __cfi_function:
    int3
    int3
    mov <id>, %eax
    int3
    int3
  function:
    ...
  ; indirect call check
    cmpl    <id>, -6(%r11)
    je      .Ltmp1
    ud2
  .Ltmp1:
    call    __x86_indirect_thunk_r11

Define the __CFI_TYPE helper macro for manually annotating indirectly
called assembly function with the identical premable, add error handling
code for the ud2 traps emitted for indirect call checks, and allow
CONFIG_CFI_CLANG to be selected on x86_64.

This produces the following oops on CFI failure (generated using lkdtm):

[   15.896503] CFI failure at lkdtm_indirect_call+0x14/0x20 [lkdtm]
(target: lkdtm_increment_int+0x0/0x7 [lkdtm]; expected type: 0x7e0c52a5)
[   15.898565] invalid opcode: 0000 [#1] PREEMPT SMP NOPTI
[   15.898798] CPU: 2 PID: 133 Comm: sh Not tainted
5.19.0-rc1-00020-g524d4b861d15 #1
[   15.898967] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014
[   15.899004] RIP: 0010:lkdtm_indirect_call+0x14/0x20 [lkdtm]
[   15.899004] Code: c7 c2 76 02 40 c0 48 c7 c1 95 00 40 c0 e9 3b cb 3e
e8 0f 1f 40 00 49 89 fb 48 c7 c7 70 64 40 c0 41 81 7b fa a5 52 0c 7f
[   15.899004] RSP: 0018:ffff9d928029fdc0 EFLAGS: 00000283
[   15.899004] RAX: 0000000000000027 RBX: ffffffffc0406320 RCX: 024cef129f458500
[   15.899004] RDX: ffffffffa9251580 RSI: ffffffffa90736c8 RDI: ffffffffc0406470
[   15.899004] RBP: 0000000000000006 R08: ffffffffa9251670 R09: 65686374616d7369
[   15.899004] R10: 000000002e2e2e20 R11: ffffffffc03fdc69 R12: 0000000000000000
[   15.899004] R13: ffff8b2c022ee000 R14: 0000000000000000 R15: 0000000000000002
[   15.899004] FS:  00007f0a6e7e86a0(0000) GS:ffff8b2c1f500000(0000)
knlGS:0000000000000000
[   15.899004] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   15.899004] CR2: 00000000010ddfd0 CR3: 0000000001bc8000 CR4: 00000000000006e0
[   15.899004] Call Trace:
[   15.899004]  <TASK>
[   15.899004]  lkdtm_CFI_FORWARD_PROTO+0x30/0x57 [lkdtm]
[   15.899004]  direct_entry+0x129/0x137 [lkdtm]
[   15.899004]  full_proxy_write+0x5b/0xa7
[   15.899004]  vfs_write+0x142/0x457
[   15.899004]  ? __x64_sys_wait4+0x5a/0xb7
[   15.899004]  ksys_write+0x69/0xd7
[   15.899004]  do_syscall_64+0x4f/0x97
[   15.899004]  entry_SYSCALL_64_after_hwframe+0x46/0xb0
[   15.899004] RIP: 0033:0x7f0a6e76dfe1
[   15.899004] Code: be 07 00 00 00 41 89 c0 e8 7e ff ff ff 44 89 c7 89
04 24 e8 91 c6 02 00 8b 04 24 48 83 c4 68 c3 48 63 ff b8 01 00 00 03
[   15.899004] RSP: 002b:00007ffe32e133c8 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
[   15.899004] RAX: ffffffffffffffda RBX: 00007f0a6e7e8690 RCX: 00007f0a6e76dfe1
[   15.899004] RDX: 0000000000000012 RSI: 0000000001ad5910 RDI: 0000000000000001
[   15.899004] RBP: 0000000000000001 R08: fefefefefefefeff R09: fefefeff00abff4e
[   15.899004] R10: 00007f0a6e7e92b0 R11: 0000000000000246 R12: 0000000001ad5910
[   15.899004] R13: 0000000000000012 R14: 00007ffe32e13501 R15: 0000000001ad2450
[   15.899004]  </TASK>
[   15.899004] Modules linked in: lkdtm
[   15.899004] Dumping ftrace buffer:
[   15.899004]    (ftrace buffer empty)
[   15.925612] ---[ end trace 0000000000000000 ]---
[   15.925661] RIP: 0010:lkdtm_indirect_call+0x14/0x20 [lkdtm]
[   15.925689] Code: c7 c2 76 02 40 c0 48 c7 c1 95 00 40 c0 e9 3b cb 3e
e8 0f 1f 40 00 49 89 fb 48 c7 c7 70 64 40 c0 41 81 7b fa a5 52 0c 7f
[   15.925697] RSP: 0018:ffff9d928029fdc0 EFLAGS: 00000283
[   15.925709] RAX: 0000000000000027 RBX: ffffffffc0406320 RCX: 024cef129f458500
[   15.925716] RDX: ffffffffa9251580 RSI: ffffffffa90736c8 RDI: ffffffffc0406470
[   15.925722] RBP: 0000000000000006 R08: ffffffffa9251670 R09: 65686374616d7369
[   15.925731] R10: 000000002e2e2e20 R11: ffffffffc03fdc69 R12: 0000000000000000
[   15.925739] R13: ffff8b2c022ee000 R14: 0000000000000000 R15: 0000000000000002
[   15.925746] FS:  00007f0a6e7e86a0(0000) GS:ffff8b2c1f500000(0000)
knlGS:0000000000000000
[   15.925755] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   15.925762] CR2: 00000000010ddfd0 CR3: 0000000001bc8000 CR4: 00000000000006e0
[   15.925889] Kernel panic - not syncing: Fatal exception

Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
---
 arch/x86/Kconfig               |  2 +
 arch/x86/include/asm/cfi.h     | 22 +++++++++
 arch/x86/include/asm/linkage.h | 12 +++++
 arch/x86/kernel/Makefile       |  2 +
 arch/x86/kernel/cfi.c          | 83 ++++++++++++++++++++++++++++++++++
 arch/x86/kernel/traps.c        |  4 +-
 6 files changed, 124 insertions(+), 1 deletion(-)
 create mode 100644 arch/x86/include/asm/cfi.h
 create mode 100644 arch/x86/kernel/cfi.c

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index be0b95e51df6..8b8c12b223ae 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -108,6 +108,8 @@ config X86
 	select ARCH_SUPPORTS_PAGE_TABLE_CHECK	if X86_64
 	select ARCH_SUPPORTS_NUMA_BALANCING	if X86_64
 	select ARCH_SUPPORTS_KMAP_LOCAL_FORCE_MAP	if NR_CPUS <= 4096
+	select ARCH_SUPPORTS_CFI_CLANG		if X86_64
+	select ARCH_USES_CFI_TRAPS		if X86_64 && CFI_CLANG
 	select ARCH_SUPPORTS_LTO_CLANG
 	select ARCH_SUPPORTS_LTO_CLANG_THIN
 	select ARCH_USE_BUILTIN_BSWAP
diff --git a/arch/x86/include/asm/cfi.h b/arch/x86/include/asm/cfi.h
new file mode 100644
index 000000000000..86a7b727ed89
--- /dev/null
+++ b/arch/x86/include/asm/cfi.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_CFI_H
+#define _ASM_X86_CFI_H
+
+/*
+ * Clang Control Flow Integrity (CFI) support.
+ *
+ * Copyright (C) 2022 Google LLC
+ */
+
+#include <linux/cfi.h>
+
+#ifdef CONFIG_CFI_CLANG
+enum bug_trap_type handle_cfi_failure(struct pt_regs *regs);
+#else
+static inline enum bug_trap_type handle_cfi_failure(struct pt_regs *regs)
+{
+	return BUG_TRAP_TYPE_NONE;
+}
+#endif /*CONFIG_CFI_CLANG */
+
+#endif /* _ASM_X86_CFI_H */
diff --git a/arch/x86/include/asm/linkage.h b/arch/x86/include/asm/linkage.h
index 85865f1645bd..0ee4a0af3974 100644
--- a/arch/x86/include/asm/linkage.h
+++ b/arch/x86/include/asm/linkage.h
@@ -25,6 +25,18 @@
 #define RET	ret
 #endif
 
+#ifdef CONFIG_CFI_CLANG
+#define __CFI_TYPE(name)					\
+	.fill 7, 1, 0xCC ASM_NL					\
+	SYM_START(__cfi_##name, SYM_L_LOCAL, SYM_A_NONE)	\
+	int3 ASM_NL						\
+	int3 ASM_NL						\
+	mov __kcfi_typeid_##name, %eax ASM_NL			\
+	int3 ASM_NL						\
+	int3 ASM_NL						\
+	SYM_FUNC_END(__cfi_##name)
+#endif
+
 #else /* __ASSEMBLY__ */
 
 #ifdef CONFIG_SLS
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 03364dc40d8d..2a3dc7e3e6ca 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -145,6 +145,8 @@ obj-$(CONFIG_UNWINDER_GUESS)		+= unwind_guess.o
 
 obj-$(CONFIG_AMD_MEM_ENCRYPT)		+= sev.o
 
+obj-$(CONFIG_CFI_CLANG)			+= cfi.o
+
 ###
 # 64 bit specific files
 ifeq ($(CONFIG_X86_64),y)
diff --git a/arch/x86/kernel/cfi.c b/arch/x86/kernel/cfi.c
new file mode 100644
index 000000000000..7954342b2b3a
--- /dev/null
+++ b/arch/x86/kernel/cfi.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Clang Control Flow Integrity (CFI) support.
+ *
+ * Copyright (C) 2022 Google LLC
+ */
+#include <asm/cfi.h>
+#include <asm/insn.h>
+#include <asm/insn-eval.h>
+
+/*
+ * Returns the target address and the expected type when regs->ip points
+ * to a compiler-generated CFI trap.
+ */
+static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target,
+			    u32 *type)
+{
+	char buffer[MAX_INSN_SIZE];
+	struct insn insn;
+	int offset = 0;
+
+	*target = *type = 0;
+
+	/*
+	 * The compiler generates the following instruction sequence
+	 * for indirect call checks:
+	 *
+	 *   cmpl    <id>, -6(%reg)	; 7-8 bytes
+	 *   je      .Ltmp1		; 2 bytes
+	 *   ud2			; <- addr
+	 *   .Ltmp1:
+	 *
+	 * Both the type and the target address can be decoded from the
+	 * cmpl instruction.
+	 */
+	if (copy_from_kernel_nofault(buffer, (void *)regs->ip - 10, MAX_INSN_SIZE))
+		return false;
+	/*
+	 * The compiler may not use r8-r15 without retpolines. Skip the
+	 * first byte if it's not the expected REX prefix.
+	 */
+	if (buffer[0] != 0x41)
+		++offset;
+	if (insn_decode_kernel(&insn, &buffer[offset]))
+		return false;
+	if (insn.opcode.value != 0x81 || X86_MODRM_REG(insn.modrm.value) != 7)
+		return false;
+
+	*type = insn.immediate.value;
+
+	/* Read the target address from the register. */
+	offset = insn_get_modrm_rm_off(&insn, regs);
+	if (offset < 0)
+		return false;
+
+	*target = *(unsigned long *)((void *)regs + offset);
+
+	return true;
+}
+
+/*
+ * Checks if a ud2 trap is because of a CFI failure, and handles the trap
+ * if needed. Returns a bug_trap_type value similarly to report_bug.
+ */
+enum bug_trap_type handle_cfi_failure(struct pt_regs *regs)
+{
+	unsigned long target;
+	u32 type;
+
+	if (!is_cfi_trap(regs->ip))
+		return BUG_TRAP_TYPE_NONE;
+
+	if (!decode_cfi_insn(regs, &target, &type))
+		return report_cfi_failure_noaddr(regs, regs->ip);
+
+	return report_cfi_failure(regs, regs->ip, &target, type);
+}
+
+/*
+ * Ensure that __kcfi_typeid_ symbols are emitted for functions that may
+ * not be indirectly called with all configurations.
+ */
+__ADDRESSABLE(memcpy)
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index d62b2cb85cea..178015a820f0 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -63,6 +63,7 @@
 #include <asm/insn-eval.h>
 #include <asm/vdso.h>
 #include <asm/tdx.h>
+#include <asm/cfi.h>
 
 #ifdef CONFIG_X86_64
 #include <asm/x86_init.h>
@@ -313,7 +314,8 @@ static noinstr bool handle_bug(struct pt_regs *regs)
 	 */
 	if (regs->flags & X86_EFLAGS_IF)
 		raw_local_irq_enable();
-	if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN) {
+	if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN ||
+	    handle_cfi_failure(regs) == BUG_TRAP_TYPE_WARN) {
 		regs->ip += LEN_UD2;
 		handled = true;
 	}
-- 
2.36.1.476.g0c4daa206d-goog


WARNING: multiple messages have this Message-ID (diff)
From: Sami Tolvanen <samitolvanen@google.com>
To: linux-kernel@vger.kernel.org
Cc: Kees Cook <keescook@chromium.org>,
	Josh Poimboeuf <jpoimboe@redhat.com>,
	 Peter Zijlstra <peterz@infradead.org>,
	x86@kernel.org,  Catalin Marinas <catalin.marinas@arm.com>,
	Will Deacon <will@kernel.org>,
	 Mark Rutland <mark.rutland@arm.com>,
	Nathan Chancellor <nathan@kernel.org>,
	 Nick Desaulniers <ndesaulniers@google.com>,
	Joao Moreira <joao@overdrivepizza.com>,
	 Sedat Dilek <sedat.dilek@gmail.com>,
	Steven Rostedt <rostedt@goodmis.org>,
	 linux-hardening@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,  llvm@lists.linux.dev,
	Sami Tolvanen <samitolvanen@google.com>
Subject: [RFC PATCH v3 20/20] x86: Add support for CONFIG_CFI_CLANG
Date: Fri, 10 Jun 2022 16:35:13 -0700	[thread overview]
Message-ID: <20220610233513.1798771-21-samitolvanen@google.com> (raw)
In-Reply-To: <20220610233513.1798771-1-samitolvanen@google.com>

With CONFIG_CFI_CLANG, the compiler injects a type preamble immediately
before each function and a check to validate the target function type
before indirect calls:

  ; type preamble
  __cfi_function:
    int3
    int3
    mov <id>, %eax
    int3
    int3
  function:
    ...
  ; indirect call check
    cmpl    <id>, -6(%r11)
    je      .Ltmp1
    ud2
  .Ltmp1:
    call    __x86_indirect_thunk_r11

Define the __CFI_TYPE helper macro for manually annotating indirectly
called assembly function with the identical premable, add error handling
code for the ud2 traps emitted for indirect call checks, and allow
CONFIG_CFI_CLANG to be selected on x86_64.

This produces the following oops on CFI failure (generated using lkdtm):

[   15.896503] CFI failure at lkdtm_indirect_call+0x14/0x20 [lkdtm]
(target: lkdtm_increment_int+0x0/0x7 [lkdtm]; expected type: 0x7e0c52a5)
[   15.898565] invalid opcode: 0000 [#1] PREEMPT SMP NOPTI
[   15.898798] CPU: 2 PID: 133 Comm: sh Not tainted
5.19.0-rc1-00020-g524d4b861d15 #1
[   15.898967] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014
[   15.899004] RIP: 0010:lkdtm_indirect_call+0x14/0x20 [lkdtm]
[   15.899004] Code: c7 c2 76 02 40 c0 48 c7 c1 95 00 40 c0 e9 3b cb 3e
e8 0f 1f 40 00 49 89 fb 48 c7 c7 70 64 40 c0 41 81 7b fa a5 52 0c 7f
[   15.899004] RSP: 0018:ffff9d928029fdc0 EFLAGS: 00000283
[   15.899004] RAX: 0000000000000027 RBX: ffffffffc0406320 RCX: 024cef129f458500
[   15.899004] RDX: ffffffffa9251580 RSI: ffffffffa90736c8 RDI: ffffffffc0406470
[   15.899004] RBP: 0000000000000006 R08: ffffffffa9251670 R09: 65686374616d7369
[   15.899004] R10: 000000002e2e2e20 R11: ffffffffc03fdc69 R12: 0000000000000000
[   15.899004] R13: ffff8b2c022ee000 R14: 0000000000000000 R15: 0000000000000002
[   15.899004] FS:  00007f0a6e7e86a0(0000) GS:ffff8b2c1f500000(0000)
knlGS:0000000000000000
[   15.899004] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   15.899004] CR2: 00000000010ddfd0 CR3: 0000000001bc8000 CR4: 00000000000006e0
[   15.899004] Call Trace:
[   15.899004]  <TASK>
[   15.899004]  lkdtm_CFI_FORWARD_PROTO+0x30/0x57 [lkdtm]
[   15.899004]  direct_entry+0x129/0x137 [lkdtm]
[   15.899004]  full_proxy_write+0x5b/0xa7
[   15.899004]  vfs_write+0x142/0x457
[   15.899004]  ? __x64_sys_wait4+0x5a/0xb7
[   15.899004]  ksys_write+0x69/0xd7
[   15.899004]  do_syscall_64+0x4f/0x97
[   15.899004]  entry_SYSCALL_64_after_hwframe+0x46/0xb0
[   15.899004] RIP: 0033:0x7f0a6e76dfe1
[   15.899004] Code: be 07 00 00 00 41 89 c0 e8 7e ff ff ff 44 89 c7 89
04 24 e8 91 c6 02 00 8b 04 24 48 83 c4 68 c3 48 63 ff b8 01 00 00 03
[   15.899004] RSP: 002b:00007ffe32e133c8 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
[   15.899004] RAX: ffffffffffffffda RBX: 00007f0a6e7e8690 RCX: 00007f0a6e76dfe1
[   15.899004] RDX: 0000000000000012 RSI: 0000000001ad5910 RDI: 0000000000000001
[   15.899004] RBP: 0000000000000001 R08: fefefefefefefeff R09: fefefeff00abff4e
[   15.899004] R10: 00007f0a6e7e92b0 R11: 0000000000000246 R12: 0000000001ad5910
[   15.899004] R13: 0000000000000012 R14: 00007ffe32e13501 R15: 0000000001ad2450
[   15.899004]  </TASK>
[   15.899004] Modules linked in: lkdtm
[   15.899004] Dumping ftrace buffer:
[   15.899004]    (ftrace buffer empty)
[   15.925612] ---[ end trace 0000000000000000 ]---
[   15.925661] RIP: 0010:lkdtm_indirect_call+0x14/0x20 [lkdtm]
[   15.925689] Code: c7 c2 76 02 40 c0 48 c7 c1 95 00 40 c0 e9 3b cb 3e
e8 0f 1f 40 00 49 89 fb 48 c7 c7 70 64 40 c0 41 81 7b fa a5 52 0c 7f
[   15.925697] RSP: 0018:ffff9d928029fdc0 EFLAGS: 00000283
[   15.925709] RAX: 0000000000000027 RBX: ffffffffc0406320 RCX: 024cef129f458500
[   15.925716] RDX: ffffffffa9251580 RSI: ffffffffa90736c8 RDI: ffffffffc0406470
[   15.925722] RBP: 0000000000000006 R08: ffffffffa9251670 R09: 65686374616d7369
[   15.925731] R10: 000000002e2e2e20 R11: ffffffffc03fdc69 R12: 0000000000000000
[   15.925739] R13: ffff8b2c022ee000 R14: 0000000000000000 R15: 0000000000000002
[   15.925746] FS:  00007f0a6e7e86a0(0000) GS:ffff8b2c1f500000(0000)
knlGS:0000000000000000
[   15.925755] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   15.925762] CR2: 00000000010ddfd0 CR3: 0000000001bc8000 CR4: 00000000000006e0
[   15.925889] Kernel panic - not syncing: Fatal exception

Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
---
 arch/x86/Kconfig               |  2 +
 arch/x86/include/asm/cfi.h     | 22 +++++++++
 arch/x86/include/asm/linkage.h | 12 +++++
 arch/x86/kernel/Makefile       |  2 +
 arch/x86/kernel/cfi.c          | 83 ++++++++++++++++++++++++++++++++++
 arch/x86/kernel/traps.c        |  4 +-
 6 files changed, 124 insertions(+), 1 deletion(-)
 create mode 100644 arch/x86/include/asm/cfi.h
 create mode 100644 arch/x86/kernel/cfi.c

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index be0b95e51df6..8b8c12b223ae 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -108,6 +108,8 @@ config X86
 	select ARCH_SUPPORTS_PAGE_TABLE_CHECK	if X86_64
 	select ARCH_SUPPORTS_NUMA_BALANCING	if X86_64
 	select ARCH_SUPPORTS_KMAP_LOCAL_FORCE_MAP	if NR_CPUS <= 4096
+	select ARCH_SUPPORTS_CFI_CLANG		if X86_64
+	select ARCH_USES_CFI_TRAPS		if X86_64 && CFI_CLANG
 	select ARCH_SUPPORTS_LTO_CLANG
 	select ARCH_SUPPORTS_LTO_CLANG_THIN
 	select ARCH_USE_BUILTIN_BSWAP
diff --git a/arch/x86/include/asm/cfi.h b/arch/x86/include/asm/cfi.h
new file mode 100644
index 000000000000..86a7b727ed89
--- /dev/null
+++ b/arch/x86/include/asm/cfi.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_CFI_H
+#define _ASM_X86_CFI_H
+
+/*
+ * Clang Control Flow Integrity (CFI) support.
+ *
+ * Copyright (C) 2022 Google LLC
+ */
+
+#include <linux/cfi.h>
+
+#ifdef CONFIG_CFI_CLANG
+enum bug_trap_type handle_cfi_failure(struct pt_regs *regs);
+#else
+static inline enum bug_trap_type handle_cfi_failure(struct pt_regs *regs)
+{
+	return BUG_TRAP_TYPE_NONE;
+}
+#endif /*CONFIG_CFI_CLANG */
+
+#endif /* _ASM_X86_CFI_H */
diff --git a/arch/x86/include/asm/linkage.h b/arch/x86/include/asm/linkage.h
index 85865f1645bd..0ee4a0af3974 100644
--- a/arch/x86/include/asm/linkage.h
+++ b/arch/x86/include/asm/linkage.h
@@ -25,6 +25,18 @@
 #define RET	ret
 #endif
 
+#ifdef CONFIG_CFI_CLANG
+#define __CFI_TYPE(name)					\
+	.fill 7, 1, 0xCC ASM_NL					\
+	SYM_START(__cfi_##name, SYM_L_LOCAL, SYM_A_NONE)	\
+	int3 ASM_NL						\
+	int3 ASM_NL						\
+	mov __kcfi_typeid_##name, %eax ASM_NL			\
+	int3 ASM_NL						\
+	int3 ASM_NL						\
+	SYM_FUNC_END(__cfi_##name)
+#endif
+
 #else /* __ASSEMBLY__ */
 
 #ifdef CONFIG_SLS
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 03364dc40d8d..2a3dc7e3e6ca 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -145,6 +145,8 @@ obj-$(CONFIG_UNWINDER_GUESS)		+= unwind_guess.o
 
 obj-$(CONFIG_AMD_MEM_ENCRYPT)		+= sev.o
 
+obj-$(CONFIG_CFI_CLANG)			+= cfi.o
+
 ###
 # 64 bit specific files
 ifeq ($(CONFIG_X86_64),y)
diff --git a/arch/x86/kernel/cfi.c b/arch/x86/kernel/cfi.c
new file mode 100644
index 000000000000..7954342b2b3a
--- /dev/null
+++ b/arch/x86/kernel/cfi.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Clang Control Flow Integrity (CFI) support.
+ *
+ * Copyright (C) 2022 Google LLC
+ */
+#include <asm/cfi.h>
+#include <asm/insn.h>
+#include <asm/insn-eval.h>
+
+/*
+ * Returns the target address and the expected type when regs->ip points
+ * to a compiler-generated CFI trap.
+ */
+static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target,
+			    u32 *type)
+{
+	char buffer[MAX_INSN_SIZE];
+	struct insn insn;
+	int offset = 0;
+
+	*target = *type = 0;
+
+	/*
+	 * The compiler generates the following instruction sequence
+	 * for indirect call checks:
+	 *
+	 *   cmpl    <id>, -6(%reg)	; 7-8 bytes
+	 *   je      .Ltmp1		; 2 bytes
+	 *   ud2			; <- addr
+	 *   .Ltmp1:
+	 *
+	 * Both the type and the target address can be decoded from the
+	 * cmpl instruction.
+	 */
+	if (copy_from_kernel_nofault(buffer, (void *)regs->ip - 10, MAX_INSN_SIZE))
+		return false;
+	/*
+	 * The compiler may not use r8-r15 without retpolines. Skip the
+	 * first byte if it's not the expected REX prefix.
+	 */
+	if (buffer[0] != 0x41)
+		++offset;
+	if (insn_decode_kernel(&insn, &buffer[offset]))
+		return false;
+	if (insn.opcode.value != 0x81 || X86_MODRM_REG(insn.modrm.value) != 7)
+		return false;
+
+	*type = insn.immediate.value;
+
+	/* Read the target address from the register. */
+	offset = insn_get_modrm_rm_off(&insn, regs);
+	if (offset < 0)
+		return false;
+
+	*target = *(unsigned long *)((void *)regs + offset);
+
+	return true;
+}
+
+/*
+ * Checks if a ud2 trap is because of a CFI failure, and handles the trap
+ * if needed. Returns a bug_trap_type value similarly to report_bug.
+ */
+enum bug_trap_type handle_cfi_failure(struct pt_regs *regs)
+{
+	unsigned long target;
+	u32 type;
+
+	if (!is_cfi_trap(regs->ip))
+		return BUG_TRAP_TYPE_NONE;
+
+	if (!decode_cfi_insn(regs, &target, &type))
+		return report_cfi_failure_noaddr(regs, regs->ip);
+
+	return report_cfi_failure(regs, regs->ip, &target, type);
+}
+
+/*
+ * Ensure that __kcfi_typeid_ symbols are emitted for functions that may
+ * not be indirectly called with all configurations.
+ */
+__ADDRESSABLE(memcpy)
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index d62b2cb85cea..178015a820f0 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -63,6 +63,7 @@
 #include <asm/insn-eval.h>
 #include <asm/vdso.h>
 #include <asm/tdx.h>
+#include <asm/cfi.h>
 
 #ifdef CONFIG_X86_64
 #include <asm/x86_init.h>
@@ -313,7 +314,8 @@ static noinstr bool handle_bug(struct pt_regs *regs)
 	 */
 	if (regs->flags & X86_EFLAGS_IF)
 		raw_local_irq_enable();
-	if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN) {
+	if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN ||
+	    handle_cfi_failure(regs) == BUG_TRAP_TYPE_WARN) {
 		regs->ip += LEN_UD2;
 		handled = true;
 	}
-- 
2.36.1.476.g0c4daa206d-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  parent reply	other threads:[~2022-06-10 23:37 UTC|newest]

Thread overview: 62+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-10 23:34 [RFC PATCH v3 00/20] KCFI support Sami Tolvanen
2022-06-10 23:34 ` Sami Tolvanen
2022-06-10 23:34 ` [RFC PATCH v3 01/20] treewide: Filter out CC_FLAGS_CFI Sami Tolvanen
2022-06-10 23:34   ` Sami Tolvanen
2022-06-10 23:34 ` [RFC PATCH v3 02/20] scripts/kallsyms: Ignore __kcfi_typeid_ Sami Tolvanen
2022-06-10 23:34   ` Sami Tolvanen
2022-06-10 23:34 ` [RFC PATCH v3 03/20] cfi: Remove CONFIG_CFI_CLANG_SHADOW Sami Tolvanen
2022-06-10 23:34   ` Sami Tolvanen
2022-06-10 23:34 ` [RFC PATCH v3 04/20] cfi: Drop __CFI_ADDRESSABLE Sami Tolvanen
2022-06-10 23:34   ` Sami Tolvanen
2022-06-10 23:34 ` [RFC PATCH v3 05/20] cfi: Switch to -fsanitize=kcfi Sami Tolvanen
2022-06-10 23:34   ` Sami Tolvanen
2022-06-10 23:34 ` [RFC PATCH v3 06/20] cfi: Add type helper macros Sami Tolvanen
2022-06-10 23:34   ` Sami Tolvanen
2022-06-10 23:35 ` [RFC PATCH v3 07/20] lkdtm: Emit an indirect call for CFI tests Sami Tolvanen
2022-06-10 23:35   ` Sami Tolvanen
2022-06-10 23:43   ` Nick Desaulniers
2022-06-10 23:43     ` Nick Desaulniers
2022-06-11  6:01   ` Kees Cook
2022-06-11  6:01     ` Kees Cook
2022-06-10 23:35 ` [RFC PATCH v3 08/20] arm64: Add types to indirect called assembly functions Sami Tolvanen
2022-06-10 23:35   ` Sami Tolvanen
2022-06-10 23:35 ` [RFC PATCH v3 09/20] arm64: Add CFI error handling Sami Tolvanen
2022-06-10 23:35   ` Sami Tolvanen
2022-06-10 23:35 ` [RFC PATCH v3 10/20] arm64: Drop unneeded __nocfi attributes Sami Tolvanen
2022-06-10 23:35   ` Sami Tolvanen
2022-06-10 23:35 ` [RFC PATCH v3 11/20] init: Drop __nocfi from __init Sami Tolvanen
2022-06-10 23:35   ` Sami Tolvanen
2022-06-10 23:35 ` [RFC PATCH v3 12/20] treewide: Drop function_nocfi Sami Tolvanen
2022-06-10 23:35   ` Sami Tolvanen
2022-06-10 23:35 ` [RFC PATCH v3 13/20] treewide: Drop WARN_ON_FUNCTION_MISMATCH Sami Tolvanen
2022-06-10 23:35   ` Sami Tolvanen
2022-06-10 23:35 ` [RFC PATCH v3 14/20] treewide: Drop __cficanonical Sami Tolvanen
2022-06-10 23:35   ` Sami Tolvanen
2022-06-10 23:35 ` [RFC PATCH v3 15/20] objtool: Disable CFI warnings Sami Tolvanen
2022-06-10 23:35   ` Sami Tolvanen
2022-06-13 16:10   ` Josh Poimboeuf
2022-06-13 16:10     ` Josh Poimboeuf
2022-06-10 23:35 ` [RFC PATCH v3 16/20] kallsyms: Drop CONFIG_CFI_CLANG workarounds Sami Tolvanen
2022-06-10 23:35   ` Sami Tolvanen
2022-06-10 23:40   ` Nick Desaulniers
2022-06-10 23:40     ` Nick Desaulniers
2022-06-13 19:19     ` Bill Wendling
2022-06-13 19:19       ` Bill Wendling
2022-06-10 23:35 ` [RFC PATCH v3 17/20] x86/tools/relocs: Ignore __kcfi_typeid_ relocations Sami Tolvanen
2022-06-10 23:35   ` Sami Tolvanen
2022-06-10 23:35 ` [RFC PATCH v3 18/20] x86: Add types to indirectly called assembly functions Sami Tolvanen
2022-06-10 23:35   ` Sami Tolvanen
2022-06-10 23:35 ` [RFC PATCH v3 19/20] x86/purgatory: Disable CFI Sami Tolvanen
2022-06-10 23:35   ` Sami Tolvanen
2022-06-10 23:35 ` Sami Tolvanen [this message]
2022-06-10 23:35   ` [RFC PATCH v3 20/20] x86: Add support for CONFIG_CFI_CLANG Sami Tolvanen
2022-07-23 11:21   ` Peter Zijlstra
2022-07-23 11:21     ` Peter Zijlstra
2022-07-26  0:09     ` Sami Tolvanen
2022-07-26  0:09       ` Sami Tolvanen
2022-06-13 17:04 ` [RFC PATCH v3 00/20] KCFI support Kees Cook
2022-06-13 17:04   ` Kees Cook
2022-07-18 21:46   ` Peter Zijlstra
2022-07-18 21:46     ` Peter Zijlstra
2022-07-19 13:36   ` Will Deacon
2022-07-19 13:36     ` Will Deacon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220610233513.1798771-21-samitolvanen@google.com \
    --to=samitolvanen@google.com \
    --cc=catalin.marinas@arm.com \
    --cc=joao@overdrivepizza.com \
    --cc=jpoimboe@redhat.com \
    --cc=keescook@chromium.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-hardening@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=llvm@lists.linux.dev \
    --cc=mark.rutland@arm.com \
    --cc=nathan@kernel.org \
    --cc=ndesaulniers@google.com \
    --cc=peterz@infradead.org \
    --cc=rostedt@goodmis.org \
    --cc=sedat.dilek@gmail.com \
    --cc=will@kernel.org \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.