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
next prev 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.