From patchwork Wed Apr 20 00:42:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joao Moreira X-Patchwork-Id: 12819532 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0E8D2C433F5 for ; Wed, 20 Apr 2022 00:43:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1358587AbiDTApr (ORCPT ); Tue, 19 Apr 2022 20:45:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58438 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244069AbiDTApm (ORCPT ); Tue, 19 Apr 2022 20:45:42 -0400 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3ACC717A93; Tue, 19 Apr 2022 17:42:57 -0700 (PDT) Received: (Authenticated sender: joao@overdrivepizza.com) by mail.gandi.net (Postfix) with ESMTPSA id 533441BF205; Wed, 20 Apr 2022 00:42:49 +0000 (UTC) From: joao@overdrivepizza.com To: linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Cc: joao@overdrivepizza.com, peterz@infradead.org, jpoimboe@redhat.com, andrew.cooper3@citrix.com, keescook@chromium.org, samitolvanen@google.com, mark.rutland@arm.com, hjl.tools@gmail.com, alyssa.milburn@linux.intel.com, ndesaulniers@google.com, gabriel.gomes@linux.intel.com, rick.p.edgecombe@intel.com Subject: [RFC PATCH 01/11] x86: kernel FineIBT Date: Tue, 19 Apr 2022 17:42:31 -0700 Message-Id: <20220420004241.2093-2-joao@overdrivepizza.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220420004241.2093-1-joao@overdrivepizza.com> References: <20220420004241.2093-1-joao@overdrivepizza.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-hardening@vger.kernel.org From: Joao Moreira Make kernel code compatible to be compiled with FineIBT. - Set FineIBT defines. - Mark functions reached from assembly as coarse-grained. - Add FineIBT handler function, which is invoked on policy violations. Signed-off-by: Joao Moreira --- arch/x86/entry/entry_64.S | 1 + arch/x86/include/asm/ibt.h | 16 ++++ arch/x86/include/asm/setup.h | 12 +-- arch/x86/include/asm/special_insns.h | 4 +- arch/x86/kernel/cpu/common.c | 2 +- arch/x86/kernel/fineibt.c | 123 +++++++++++++++++++++++++++ arch/x86/kernel/head64.c | 12 +-- arch/x86/kernel/smpboot.c | 2 +- 8 files changed, 156 insertions(+), 16 deletions(-) create mode 100644 arch/x86/kernel/fineibt.c diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index 4faac48ebec5..901b702fb16d 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -295,6 +295,7 @@ SYM_CODE_START(ret_from_fork) /* kernel thread */ UNWIND_HINT_EMPTY movq %r12, %rdi + FINEIBT_HASH(0x89f22991) CALL_NOSPEC rbx /* * A kernel thread is allowed to return here after successfully diff --git a/arch/x86/include/asm/ibt.h b/arch/x86/include/asm/ibt.h index 689880eca9ba..580aa8b83bb2 100644 --- a/arch/x86/include/asm/ibt.h +++ b/arch/x86/include/asm/ibt.h @@ -21,6 +21,16 @@ #define HAS_KERNEL_IBT 1 +#if defined(CONFIG_X86_KERNEL_FINEIBT) && !defined(BUILD_VDSO) && !defined(BUILD_VDSO32_64) +#define HAS_KERNEL_FINEIBT 1 +#define FINEIBT_HASH(hash) mov $hash, %r11d +#define __coarseendbr __attribute__((coarsecf_check)) +#else +#define HAS_KERNEL_FINEIBT 0 +#define FINEIBT_HASH(hash) +#define __coarseendbr +#endif + #ifndef __ASSEMBLY__ #ifdef CONFIG_X86_64 @@ -29,6 +39,7 @@ #define ASM_ENDBR "endbr32\n\t" #endif +#undef __noendbr #define __noendbr __attribute__((nocf_check)) static inline __attribute_const__ u32 gen_endbr(void) @@ -80,12 +91,17 @@ extern __noendbr void ibt_restore(u64 save); #else /* !IBT */ #define HAS_KERNEL_IBT 0 +#define HAS_KERNEL_FINEIBT 0 +#define FINEIBT_HASH(hash) #ifndef __ASSEMBLY__ #define ASM_ENDBR +#undef __noendbr #define __noendbr +#undef __coarseendbr +#define __coarseendbr static inline bool is_endbr(u32 val) { return false; } diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index 896e48d45828..d2a2f6456403 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h @@ -49,10 +49,10 @@ extern unsigned long saved_video_mode; extern void reserve_standard_io_resources(void); extern void i386_reserve_resources(void); -extern unsigned long __startup_64(unsigned long physaddr, struct boot_params *bp); -extern unsigned long __startup_secondary_64(void); -extern void startup_64_setup_env(unsigned long physbase); -extern void early_setup_idt(void); +extern unsigned long __coarseendbr __startup_64(unsigned long physaddr, struct boot_params *bp); +extern unsigned long __coarseendbr __startup_secondary_64(void); +extern void __coarseendbr startup_64_setup_env(unsigned long physbase); +extern void __coarseendbr early_setup_idt(void); extern void __init do_early_exception(struct pt_regs *regs, int trapnr); #ifdef CONFIG_X86_INTEL_MID @@ -137,8 +137,8 @@ extern void probe_roms(void); asmlinkage void __init i386_start_kernel(void); #else -asmlinkage void __init x86_64_start_kernel(char *real_mode); -asmlinkage void __init x86_64_start_reservations(char *real_mode_data); +asmlinkage void __init __coarseendbr x86_64_start_kernel(char *real_mode); +asmlinkage void __init __coarseendbr x86_64_start_reservations(char *real_mode_data); #endif /* __i386__ */ #endif /* _SETUP */ diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h index 68c257a3de0d..7f32ef8d23f0 100644 --- a/arch/x86/include/asm/special_insns.h +++ b/arch/x86/include/asm/special_insns.h @@ -49,7 +49,7 @@ static inline unsigned long __native_read_cr3(void) return val; } -static inline void native_write_cr3(unsigned long val) +static inline void __coarseendbr native_write_cr3(unsigned long val) { asm volatile("mov %0,%%cr3": : "r" (val) : "memory"); } @@ -74,7 +74,7 @@ static inline unsigned long native_read_cr4(void) return val; } -void native_write_cr4(unsigned long val); +void __coarseendbr native_write_cr4(unsigned long val); #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS static inline u32 rdpkru(void) diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index ed4417500700..70e94194ee2b 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -463,7 +463,7 @@ void native_write_cr0(unsigned long val) } EXPORT_SYMBOL(native_write_cr0); -void __no_profile native_write_cr4(unsigned long val) +void __no_profile __coarseendbr native_write_cr4(unsigned long val) { unsigned long bits_changed = 0; diff --git a/arch/x86/kernel/fineibt.c b/arch/x86/kernel/fineibt.c new file mode 100644 index 000000000000..685e4308d86e --- /dev/null +++ b/arch/x86/kernel/fineibt.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file contains the FineIBT handler function. + */ + +#include +#include +#include +#include +#include + +void __noendbr __fineibt_handler(void); + +void __fineibt_debug(void) { + asm volatile ("nop\n"); + printk("fineibt debug\n"); +}; +EXPORT_SYMBOL(__fineibt_debug); + +#define FINEIBT_VADDR_LEN 4096 +#define DO_ALL_PUSHS \ + asm("nop\n\t" \ + "push %rsi\n\t" \ + "push %rdi\n\t" \ + "push %rdx\n\t" \ + "push %rcx\n\t" \ + "push %rbx\n\t" \ + "push %rax\n\t" \ + "push %r8\n\t" \ + "push %r9\n\t" \ + "push %r10\n\t" \ + "push %r11\n\t" \ + "push %r12\n\t" \ + "push %r13\n\t" \ + "push %r14\n\t" \ + "push %r15\n\t") + +#define DO_ALL_POPS \ + asm("nop\n\t" \ + "pop %r15\n\t" \ + "pop %r14\n\t" \ + "pop %r13\n\t" \ + "pop %r12\n\t" \ + "pop %r11\n\t" \ + "pop %r10\n\t" \ + "pop %r9\n\t" \ + "pop %r8\n\t" \ + "pop %rax\n\t" \ + "pop %rbx\n\t" \ + "pop %rcx\n\t" \ + "pop %rdx\n\t" \ + "pop %rdi\n\t" \ + "pop %rsi\n\t") + +struct fineibt_violation{ + void * vaddr; + void * caddr; + bool printed; +}; + +typedef struct fineibt_violation fineibt_violation; + +static fineibt_violation vlts[FINEIBT_VADDR_LEN]; +static unsigned long vlts_next = 0; +static bool vlts_initialize = true; +static DEFINE_SPINLOCK(fineibt_lock); + +void __noendbr __fineibt_handler(void){ + unsigned i; + unsigned long flags; + bool skip; + void * ret; + void * caller; + + DO_ALL_PUSHS; + + spin_lock_irqsave(&fineibt_lock, flags); + skip = false; + + asm("\t movq 0x90(%%rsp),%0" : "=r"(ret)); + asm("\t movq 0x98(%%rsp),%0" : "=r"(caller)); + + if(vlts_initialize){ + for(i = 0; i < FINEIBT_VADDR_LEN; i++) { + vlts[i].vaddr = 0; + vlts[i].caddr = 0; + vlts[i].printed = 0; + } + vlts_initialize = false; + } + + if(vlts_next >= FINEIBT_VADDR_LEN) { + if(vlts_next == FINEIBT_VADDR_LEN) { + printk("FineIBT reached max buffer\n"); + vlts_next++; + } + skip = true; + } + + for(i = 0; i < vlts_next; i++){ + if(vlts[i].vaddr == ret && vlts[i].caddr == caller) { + skip = true; + break; + } + } + + if(!skip) { + vlts[vlts_next].vaddr = ret; + vlts[vlts_next].caddr = caller; + vlts[vlts_next].printed = 0; + vlts_next = vlts_next + 1; + } + + spin_unlock_irqrestore(&fineibt_lock, flags); + + if(!skip) { + printk("FineIBT violation: %px:%px:%u\n", ret, caller, + vlts_next); + } + DO_ALL_POPS; +} + +EXPORT_SYMBOL(__fineibt_handler); diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index 4f5ecbbaae77..f773d771e07d 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c @@ -162,7 +162,7 @@ static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdv * boot-time crashes. To work around this problem, every global pointer must * be adjusted using fixup_pointer(). */ -unsigned long __head __startup_64(unsigned long physaddr, +unsigned long __head __coarseendbr __startup_64(unsigned long physaddr, struct boot_params *bp) { unsigned long load_delta, *p; @@ -308,7 +308,7 @@ unsigned long __head __startup_64(unsigned long physaddr, return sme_postprocess_startup(bp, pmd); } -unsigned long __startup_secondary_64(void) +unsigned long __coarseendbr __startup_secondary_64(void) { /* * Return the SME encryption mask (if SME is active) to be used as a @@ -464,8 +464,8 @@ static void __init copy_bootdata(char *real_mode_data) sme_unmap_bootdata(real_mode_data); } -asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data) -{ +asmlinkage __visible void __init __coarseendbr +x86_64_start_kernel(char * real_mode_data) { /* * Build-time sanity checks on the kernel image and module * area mappings. (these are purely build-time and produce no code) @@ -597,7 +597,7 @@ static void startup_64_load_idt(unsigned long physbase) } /* This is used when running on kernel addresses */ -void early_setup_idt(void) +void __coarseendbr early_setup_idt(void) { /* VMM Communication Exception */ if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)) @@ -610,7 +610,7 @@ void early_setup_idt(void) /* * Setup boot CPU state needed before kernel switches to virtual addresses. */ -void __head startup_64_setup_env(unsigned long physbase) +void __head __coarseendbr startup_64_setup_env(unsigned long physbase) { /* Load GDT */ startup_gdt_descr.address = (unsigned long)fixup_pointer(startup_gdt, physbase); diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 2ef14772dc04..5fa17d5716bb 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -214,7 +214,7 @@ static int enable_start_cpu0; /* * Activate a secondary processor. */ -static void notrace start_secondary(void *unused) +static void notrace __coarseendbr start_secondary(void *unused) { /* * Don't put *anything* except direct CPU state initialization From patchwork Wed Apr 20 00:42:32 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joao Moreira X-Patchwork-Id: 12819533 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 63539C433EF for ; Wed, 20 Apr 2022 00:43:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1358589AbiDTAps (ORCPT ); Tue, 19 Apr 2022 20:45:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58500 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1358585AbiDTApr (ORCPT ); Tue, 19 Apr 2022 20:45:47 -0400 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 385042F3BE; Tue, 19 Apr 2022 17:43:03 -0700 (PDT) Received: (Authenticated sender: joao@overdrivepizza.com) by mail.gandi.net (Postfix) with ESMTPSA id 799551BF208; Wed, 20 Apr 2022 00:42:56 +0000 (UTC) From: joao@overdrivepizza.com To: linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Cc: joao@overdrivepizza.com, peterz@infradead.org, jpoimboe@redhat.com, andrew.cooper3@citrix.com, keescook@chromium.org, samitolvanen@google.com, mark.rutland@arm.com, hjl.tools@gmail.com, alyssa.milburn@linux.intel.com, ndesaulniers@google.com, gabriel.gomes@linux.intel.com, rick.p.edgecombe@intel.com Subject: [RFC PATCH 02/11] kbuild: Support FineIBT build Date: Tue, 19 Apr 2022 17:42:32 -0700 Message-Id: <20220420004241.2093-3-joao@overdrivepizza.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220420004241.2093-1-joao@overdrivepizza.com> References: <20220420004241.2093-1-joao@overdrivepizza.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-hardening@vger.kernel.org From: Joao Moreira Add FineIBT compilation flags to Makefiles, preserving translation units which should not get it. Signed-off-by: Joao Moreira --- arch/x86/Kconfig | 10 ++++++++++ arch/x86/Makefile | 3 +++ arch/x86/entry/vdso/Makefile | 5 +++++ arch/x86/kernel/Makefile | 1 + arch/x86/purgatory/Makefile | 4 ++++ 5 files changed, 23 insertions(+) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index b0142e01002e..37e49e9187a0 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1872,6 +1872,16 @@ config X86_KERNEL_IBT does significantly reduce the number of ENDBR instructions in the kernel image. +config CC_HAS_FINEIBT + def_bool $(cc-option, -fcf-protection=branch -mfine-ibt) && $(as-instr,endbr64) + +config X86_KERNEL_FINEIBT + prompt "Fine-grain Indirect Branch Tracking" + bool + depends on X86_KERNEL_IBT && CC_HAS_FINEIBT + help + Build the kernel with Fine-grained IBT. + config X86_INTEL_MEMORY_PROTECTION_KEYS prompt "Memory Protection Keys" def_bool y diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 63d50f65b828..768e318eb78f 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -73,6 +73,9 @@ ifeq ($(CONFIG_X86_KERNEL_IBT),y) # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104816 # KBUILD_CFLAGS += $(call cc-option,-fcf-protection=branch -fno-jump-tables) +ifeq ($(CONFIG_X86_KERNEL_FINEIBT),y) +KBUILD_CFLAGS += $(call cc-option, -mfine-ibt) +endif else KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none) endif diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile index 693f8b9031fb..3dce5571460e 100644 --- a/arch/x86/entry/vdso/Makefile +++ b/arch/x86/entry/vdso/Makefile @@ -91,7 +91,11 @@ ifneq ($(RETPOLINE_VDSO_CFLAGS),) endif endif +ifdef CONFIG_X86_KERNEL_FINEIBT +$(vobjs): KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_LTO) $(GCC_PLUGINS_CFLAGS) $(RETPOLINE_CFLAGS) -mfine-ibt,$(KBUILD_CFLAGS)) $(CFL) +else $(vobjs): KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_LTO) $(GCC_PLUGINS_CFLAGS) $(RETPOLINE_CFLAGS),$(KBUILD_CFLAGS)) $(CFL) +endif # # vDSO code runs in userspace and -pg doesn't help with profiling anyway. @@ -151,6 +155,7 @@ KBUILD_CFLAGS_32 := $(filter-out -mfentry,$(KBUILD_CFLAGS_32)) KBUILD_CFLAGS_32 := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS_32)) KBUILD_CFLAGS_32 := $(filter-out $(RETPOLINE_CFLAGS),$(KBUILD_CFLAGS_32)) KBUILD_CFLAGS_32 := $(filter-out $(CC_FLAGS_LTO),$(KBUILD_CFLAGS_32)) +KBUILD_CFLAGS_32 := $(filter-out -mfine-ibt,$(KBUILD_CFLAGS_32)) KBUILD_CFLAGS_32 += -m32 -msoft-float -mregparm=0 -fpic KBUILD_CFLAGS_32 += -fno-stack-protector KBUILD_CFLAGS_32 += $(call cc-option, -foptimize-sibling-calls) diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index c41ef42adbe8..cb947569e9d8 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -148,6 +148,7 @@ obj-$(CONFIG_UNWINDER_FRAME_POINTER) += unwind_frame.o obj-$(CONFIG_UNWINDER_GUESS) += unwind_guess.o obj-$(CONFIG_AMD_MEM_ENCRYPT) += sev.o +obj-$(CONFIG_X86_KERNEL_FINEIBT) += fineibt.o ### # 64 bit specific files diff --git a/arch/x86/purgatory/Makefile b/arch/x86/purgatory/Makefile index ae53d54d7959..e16b25a598ba 100644 --- a/arch/x86/purgatory/Makefile +++ b/arch/x86/purgatory/Makefile @@ -55,6 +55,10 @@ ifdef CONFIG_RETPOLINE PURGATORY_CFLAGS_REMOVE += $(RETPOLINE_CFLAGS) endif +ifdef CONFIG_X86_KERNEL_FINEIBT +PURGATORY_CFLAGS_REMOVE += -mfine-ibt +endif + CFLAGS_REMOVE_purgatory.o += $(PURGATORY_CFLAGS_REMOVE) CFLAGS_purgatory.o += $(PURGATORY_CFLAGS) From patchwork Wed Apr 20 00:42:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joao Moreira X-Patchwork-Id: 12819534 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A485EC433EF for ; Wed, 20 Apr 2022 00:43:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1358585AbiDTAp6 (ORCPT ); Tue, 19 Apr 2022 20:45:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58584 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1358601AbiDTApz (ORCPT ); Tue, 19 Apr 2022 20:45:55 -0400 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 42ADA27CF5; Tue, 19 Apr 2022 17:43:09 -0700 (PDT) Received: (Authenticated sender: joao@overdrivepizza.com) by mail.gandi.net (Postfix) with ESMTPSA id 74EAF1BF203; Wed, 20 Apr 2022 00:43:02 +0000 (UTC) From: joao@overdrivepizza.com To: linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Cc: joao@overdrivepizza.com, peterz@infradead.org, jpoimboe@redhat.com, andrew.cooper3@citrix.com, keescook@chromium.org, samitolvanen@google.com, mark.rutland@arm.com, hjl.tools@gmail.com, alyssa.milburn@linux.intel.com, ndesaulniers@google.com, gabriel.gomes@linux.intel.com, rick.p.edgecombe@intel.com Subject: [RFC PATCH 03/11] objtool: Support FineIBT offset fixes Date: Tue, 19 Apr 2022 17:42:33 -0700 Message-Id: <20220420004241.2093-4-joao@overdrivepizza.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220420004241.2093-1-joao@overdrivepizza.com> References: <20220420004241.2093-1-joao@overdrivepizza.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-hardening@vger.kernel.org From: Joao Moreira Direct branches can't go into FineIBT hash check operations. Identify these in the binary and correct the branch offset to skip it. If the offset correction cannot be placed because the operand is too small for the jump, patch the FineIBT hash check operation with nops. This patch is a re-spin of Peter Zijlstra's objtool support from the IBT series V2. Signed-off-by: Joao Moreira Tinkered-from-patches-by: Peter Zijlstra --- scripts/link-vmlinux.sh | 8 + tools/objtool/arch/x86/decode.c | 175 +++++++++++++---- tools/objtool/arch/x86/include/arch/special.h | 2 + tools/objtool/builtin-check.c | 3 +- tools/objtool/check.c | 183 +++++++++++++++++- tools/objtool/include/objtool/arch.h | 3 + tools/objtool/include/objtool/builtin.h | 2 +- 7 files changed, 332 insertions(+), 44 deletions(-) diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 20f44504a644..2d657c0232ee 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -126,6 +126,10 @@ objtool_link() if is_enabled CONFIG_FTRACE_MCOUNT_USE_OBJTOOL; then objtoolopt="${objtoolopt} --mcount" fi + + if is_enabled CONFIG_X86_KERNEL_FINEIBT; then + objtoolopt="${objtoolopt} --fineibt" + fi fi if is_enabled CONFIG_VMLINUX_VALIDATION; then @@ -152,6 +156,9 @@ objtool_link() if is_enabled CONFIG_SLS; then objtoolopt="${objtoolopt} --sls" fi + if is_enabled CONFIG_X86_KERNEL_FINEIBT; then + objtoolopt="${objtoolopt} --fineibt" + fi info OBJTOOL ${1} tools/objtool/objtool ${objtoolcmd} ${objtoolopt} ${1} fi @@ -175,6 +182,7 @@ vmlinux_link() shift if is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT; then + #if is_enabled CONFIG_LTO_CLANG; then # Use vmlinux.o instead of performing the slow LTO link again. objs=vmlinux.o libs= diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index 943cb41cddf7..766a234faa03 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -22,6 +22,7 @@ #include #include #include +#include static int is_x86_64(const struct elf *elf) { @@ -241,54 +242,61 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec * 011 SBB 111 CMP */ - /* 64bit only */ - if (!rex_w) - break; + /* %rsp target */ + if (rm_is_reg(CFI_SP)) { - /* %rsp target only */ - if (!rm_is_reg(CFI_SP)) - break; + /* 64 bit only */ + if (!rex_w) + break; - imm = insn.immediate.value; - if (op1 & 2) { /* sign extend */ - if (op1 & 1) { /* imm32 */ - imm <<= 32; - imm = (s64)imm >> 32; - } else { /* imm8 */ - imm <<= 56; - imm = (s64)imm >> 56; + imm = insn.immediate.value; + if (op1 & 2) { /* sign extend */ + if (op1 & 1) { /* imm32 */ + imm <<= 32; + imm = (s64)imm >> 32; + } else { /* imm8 */ + imm <<= 56; + imm = (s64)imm >> 56; + } } - } - switch (modrm_reg & 7) { - case 5: - imm = -imm; - /* fallthrough */ - case 0: - /* add/sub imm, %rsp */ - ADD_OP(op) { - op->src.type = OP_SRC_ADD; - op->src.reg = CFI_SP; - op->src.offset = imm; - op->dest.type = OP_DEST_REG; - op->dest.reg = CFI_SP; - } - break; + switch (modrm_reg & 7) { + case 5: + imm = -imm; + /* fallthrough */ + case 0: + /* add/sub imm, %rsp */ + ADD_OP(op) { + op->src.type = OP_SRC_ADD; + op->src.reg = CFI_SP; + op->src.offset = imm; + op->dest.type = OP_DEST_REG; + op->dest.reg = CFI_SP; + } + break; - case 4: - /* and imm, %rsp */ - ADD_OP(op) { - op->src.type = OP_SRC_AND; - op->src.reg = CFI_SP; - op->src.offset = insn.immediate.value; - op->dest.type = OP_DEST_REG; - op->dest.reg = CFI_SP; + case 4: + /* and imm, %rsp */ + ADD_OP(op) { + op->src.type = OP_SRC_AND; + op->src.reg = CFI_SP; + op->src.offset = insn.immediate.value; + op->dest.type = OP_DEST_REG; + op->dest.reg = CFI_SP; + } + break; + + default: + /* WARN ? */ + break; } - break; + } - default: - /* WARN ? */ - break; + if (rm_is_reg(CFI_R11)) { + if (op1 == 0x81) { + *type = INSN_SUB_R11; + break; + } } break; @@ -729,6 +737,91 @@ const char *arch_nop_insn(int len) return nops[len-1]; } +const char *arch_bypass_fineibt() +{ + // FineIBT skip is: + // xor r11, r11 (to destroy any hash contents in r11 and prevent reuse) + // jmp (jump to the beginning of function and skip whatever) + + // AFTER_FINEIBT = FineIBT len - endbr len - xor len - jmp len +#define AFTER_FINEIBT FINEIBT_FIXUP - 4 - 3 - 2 + static const char bytes[7] = { 0x4d, 0x31, 0xdb, 0xeb, + AFTER_FINEIBT , BYTES_NOP2}; + return bytes; +} + +const char *arch_mod_immediate(struct instruction *insn, unsigned long target) +{ + struct section *sec = insn->sec; + Elf_Data *data = sec->data; + unsigned char op1, op2; + static char bytes[16]; + struct insn x86_insn; + int ret, disp; + + disp = (long)(target - (insn->offset + insn->len)); + + if (data->d_type != ELF_T_BYTE || data->d_off) { + WARN("unexpected data for section: %s", sec->name); + return NULL; + } + + ret = insn_decode(&x86_insn, data->d_buf + insn->offset, insn->len, + INSN_MODE_64); + if (ret < 0) { + WARN("can't decode instruction at %s:0x%lx", sec->name, + insn->offset); + return NULL; + } + + op1 = x86_insn.opcode.bytes[0]; + op2 = x86_insn.opcode.bytes[1]; + + switch (op1) { + case 0x0f: /* escape */ + switch (op2) { + case 0x80 ... 0x8f: /* jcc.d32 */ + if (insn->len != 6) + return NULL; + bytes[0] = op1; + bytes[1] = op2; + *(int *)&bytes[2] = disp; + break; + + default: + return NULL; + } + break; + + case 0x70 ... 0x7f: /* jcc.d8 */ + case 0xeb: /* jmp.d8 */ + if (insn->len != 2) + return NULL; + + if (disp >> 7 != disp >> 31) { + WARN("Jump displacement doesn't fit"); + return NULL; + } + + bytes[0] = op1; + bytes[1] = disp & 0xff; + break; + + case 0xe8: /* call */ + case 0xe9: /* jmp.d32 */ + if (insn->len != 5) + return NULL; + bytes[0] = op1; + *(int *)&bytes[1] = disp; + break; + + default: + return NULL; + } + + return bytes; +} + #define BYTE_RET 0xC3 const char *arch_ret_insn(int len) diff --git a/tools/objtool/arch/x86/include/arch/special.h b/tools/objtool/arch/x86/include/arch/special.h index f2918f789a0a..f36525ecc7ec 100644 --- a/tools/objtool/arch/x86/include/arch/special.h +++ b/tools/objtool/arch/x86/include/arch/special.h @@ -18,4 +18,6 @@ #define ALT_ORIG_LEN_OFFSET 10 #define ALT_NEW_LEN_OFFSET 11 +#define FINEIBT_FIXUP 18 + #endif /* _X86_ARCH_SPECIAL_H */ diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index fc6975ab8b06..2b3813726605 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -21,7 +21,7 @@ bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats, lto, vmlinux, mcount, noinstr, backup, sls, dryrun, - ibt; + ibt, fineibt; static const char * const check_usage[] = { "objtool check [] file.o", @@ -49,6 +49,7 @@ const struct option check_options[] = { OPT_BOOLEAN('S', "sls", &sls, "validate straight-line-speculation"), OPT_BOOLEAN(0, "dry-run", &dryrun, "don't write the modifications"), OPT_BOOLEAN(0, "ibt", &ibt, "validate ENDBR placement"), + OPT_BOOLEAN(0, "fineibt", &fineibt, "fix FineIBT direct calls"), OPT_END(), }; diff --git a/tools/objtool/check.c b/tools/objtool/check.c index bd0c2c828940..e5b85ad40454 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -27,7 +28,7 @@ struct alternative { bool skip_orig; }; -static unsigned long nr_cfi, nr_cfi_reused, nr_cfi_cache; +static unsigned long nr_cfi, nr_cfi_reused, nr_cfi_cache, nr_fineibt; static struct cfi_init_state initial_func_cfi; static struct cfi_state init_cfi; @@ -1211,6 +1212,173 @@ static void add_call_dest(struct objtool_file *file, struct instruction *insn, annotate_call_site(file, insn, sibling); } +static bool is_fineibt_sequence(struct objtool_file *file, + struct section *dest_sec, unsigned long dest_off) { + + struct instruction *insn; + + insn = find_insn(file, dest_sec, dest_off); + if (insn->type != INSN_ENDBR) + return false; + + insn = find_insn(file, dest_sec, dest_off+4); + arch_decode_instruction(file, dest_sec, dest_off+4, + dest_sec->sh.sh_size - (dest_off+4), + &insn->len, &insn->type, &insn->immediate, + &insn->stack_ops); + if (insn->type != INSN_SUB_R11) + return false; + + insn = find_insn(file, dest_sec, dest_off+11); + arch_decode_instruction(file, dest_sec, dest_off+11, + dest_sec->sh.sh_size - (dest_off+11), + &insn->len, &insn->type, &insn->immediate, + &insn->stack_ops); + if (insn->type != INSN_JUMP_CONDITIONAL) + return false; + + // XXX: when call __fineibt_handler is replaced by ud2, check it here. + return true; +} + +static bool nopout_jmp_target(struct objtool_file *file, + struct instruction *jmp) { + struct instruction *tgt = jmp->jump_dest; + const char *op = arch_bypass_fineibt(); + + if (is_fineibt_sequence(file, tgt->sec, tgt->offset)) { + tgt = next_insn_same_func(file, tgt); + elf_write_insn(file->elf, tgt->sec, tgt->offset, 7, op); + return true; + } + return false; +} + +static void fix_fineibt_call(struct objtool_file *file, + struct instruction *insn) { + + unsigned long dest_off; + struct instruction *target = NULL; + struct reloc *reloc = insn_reloc(file, insn); + const char *op = NULL; + + if (!reloc) { + dest_off = arch_jump_destination(insn); + target = find_insn(file, insn->sec, + dest_off); + + } else if (reloc->sym->retpoline_thunk) { + return; + + } else { + dest_off = reloc->sym->offset + + arch_dest_reloc_offset(reloc->addend); + target = find_insn(file, reloc->sym->sec, dest_off); + } + + if (target && target->type == INSN_ENDBR + && is_fineibt_sequence(file, target->sec, dest_off)) { + if (reloc) { + reloc->addend += FINEIBT_FIXUP; + elf_write_reloc(file->elf, reloc); + } else { + op = arch_mod_immediate(insn, dest_off + FINEIBT_FIXUP); + if (op) { + elf_write_insn(file->elf, insn->sec, + insn->offset, insn->len, op); + } else { + WARN_FUNC("Can't fix direct call to FineIBT", + insn->sec, insn->offset); + return; + } + } + } +} + +static void fix_fineibt_jump(struct objtool_file *file, + struct instruction *insn) { + + unsigned long dest_off; + struct section *dest_sec; + struct reloc *reloc = insn_reloc(file, insn); + const char *op = NULL; + + if (!reloc) { + dest_sec = insn->sec; + dest_off = arch_jump_destination(insn); + + } else if (reloc->sym->type == STT_SECTION) { + dest_sec = reloc->sym->sec; + dest_off = arch_dest_reloc_offset(reloc->addend); + + } else if (reloc->sym->retpoline_thunk) { + return; + + } else if (insn->func || reloc->sym->sec->idx) { + dest_sec = reloc->sym->sec; + dest_off = reloc->sym->offset + + arch_dest_reloc_offset(reloc->addend); + } else { + return; + } + + insn->jump_dest = find_insn(file, dest_sec, dest_off); + if (!insn->jump_dest) { + if (!vmlinux && insn->func) { + dest_sec = insn->func->sec; + dest_off = insn->func->offset; + } else if (!strcmp(insn->sec->name, ".altinstr_replacement")) { + /* XXX: corner case unclear if fineibt-relevant */ + return; + } + } + + if (insn->jump_dest->type == INSN_ENDBR && + is_fineibt_sequence(file, insn->jump_dest->sec, + dest_off)) { + if (reloc) { + reloc->addend += FINEIBT_FIXUP; + elf_write_reloc(file->elf, reloc); + return; + } + op = arch_mod_immediate(insn, dest_off + FINEIBT_FIXUP); + if (op) { + elf_write_insn(file->elf, insn->sec, insn->offset, + insn->len, op); + return; + } + if (nopout_jmp_target(file, insn)) { + WARN_FUNC("Can't fix direct jump to FineIBT", + insn->sec, insn->offset); + return; + } else { + WARN_FUNC("Can't fix direct jump to FineIBT", + insn->sec, insn->offset); + return; + } + } +} + +static bool fix_fineibt_branches(struct objtool_file *file) { + struct instruction *insn; + struct section *sec; + + for_each_sec(file, sec) { + if (!sec->text) { + continue; + } + + sec_for_each_insn(file, sec, insn) { + if (insn->type == INSN_CALL) { + fix_fineibt_call(file, insn); + } else if (is_static_jump(insn)) { + fix_fineibt_jump(file, insn); + } + } + } + return 0; +} + static void add_retpoline_call(struct objtool_file *file, struct instruction *insn) { /* @@ -3859,6 +4027,11 @@ int check(struct objtool_file *file) return 1; } + if (fineibt && !ibt) { + fprintf(stderr, "--fineibt requires: --ibt\n"); + return 1; + } + arch_initial_func_cfi_state(&initial_func_cfi); init_cfi_state(&init_cfi); init_cfi_state(&func_cfi); @@ -3945,11 +4118,19 @@ int check(struct objtool_file *file) warnings += ret; } + if (fineibt) { + ret = fix_fineibt_branches(file); + if (ret < 0) + goto out; + warnings += ret; + } + if (stats) { printf("nr_insns_visited: %ld\n", nr_insns_visited); printf("nr_cfi: %ld\n", nr_cfi); printf("nr_cfi_reused: %ld\n", nr_cfi_reused); printf("nr_cfi_cache: %ld\n", nr_cfi_cache); + if (fineibt) printf("nr_fineibt_entries: %ld\n", nr_fineibt); } out: diff --git a/tools/objtool/include/objtool/arch.h b/tools/objtool/include/objtool/arch.h index 9b19cc304195..9c12770ccd13 100644 --- a/tools/objtool/include/objtool/arch.h +++ b/tools/objtool/include/objtool/arch.h @@ -28,6 +28,7 @@ enum insn_type { INSN_CLD, INSN_TRAP, INSN_ENDBR, + INSN_SUB_R11, INSN_OTHER, }; @@ -85,6 +86,8 @@ unsigned long arch_dest_reloc_offset(int addend); const char *arch_nop_insn(int len); const char *arch_ret_insn(int len); +const char *arch_mod_immediate(struct instruction *insn, unsigned long target); +const char *arch_bypass_fineibt(void); int arch_decode_hint_reg(u8 sp_reg, int *base); diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h index c39dbfaef6dc..801eaeae1627 100644 --- a/tools/objtool/include/objtool/builtin.h +++ b/tools/objtool/include/objtool/builtin.h @@ -10,7 +10,7 @@ extern const struct option check_options[]; extern bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats, lto, vmlinux, mcount, noinstr, backup, sls, dryrun, - ibt; + ibt, fineibt; extern int cmd_parse_options(int argc, const char **argv, const char * const usage[]); From patchwork Wed Apr 20 00:42:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joao Moreira X-Patchwork-Id: 12819535 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EE8FAC433EF for ; Wed, 20 Apr 2022 00:43:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1358625AbiDTAqT (ORCPT ); Tue, 19 Apr 2022 20:46:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58700 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1358616AbiDTAqD (ORCPT ); Tue, 19 Apr 2022 20:46:03 -0400 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C5A8817A93; Tue, 19 Apr 2022 17:43:17 -0700 (PDT) Received: (Authenticated sender: joao@overdrivepizza.com) by mail.gandi.net (Postfix) with ESMTPSA id 964FC1BF205; Wed, 20 Apr 2022 00:43:08 +0000 (UTC) From: joao@overdrivepizza.com To: linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Cc: joao@overdrivepizza.com, peterz@infradead.org, jpoimboe@redhat.com, andrew.cooper3@citrix.com, keescook@chromium.org, samitolvanen@google.com, mark.rutland@arm.com, hjl.tools@gmail.com, alyssa.milburn@linux.intel.com, ndesaulniers@google.com, gabriel.gomes@linux.intel.com, rick.p.edgecombe@intel.com Subject: [RFC PATCH 04/11] x86/module: Support FineIBT in modules Date: Tue, 19 Apr 2022 17:42:34 -0700 Message-Id: <20220420004241.2093-5-joao@overdrivepizza.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220420004241.2093-1-joao@overdrivepizza.com> References: <20220420004241.2093-1-joao@overdrivepizza.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-hardening@vger.kernel.org From: Joao Moreira Identify direct branch relocations targeting FineIBT hash check sequence and fix the offset to bypass it. Invoke objtool with fineibt flag for modules to fix in-module direct branches too. Signed-off-by: Joao Moreira Tinkered-from-patches-by: Peter Zijlstra --- arch/x86/kernel/module.c | 45 +++++++++++++++++++++++++++++++++++++--- scripts/Makefile.build | 1 + 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index b98ffcf4d250..4afe71ae3e56 100644 --- a/arch/x86/kernel/module.c +++ b/arch/x86/kernel/module.c @@ -128,6 +128,41 @@ int apply_relocate(Elf32_Shdr *sechdrs, return 0; } #else /*X86_64*/ + +// shamelessly reshaped from PeterZ's IBT patches v2 +static inline void fineibt_branch_fix(void *loc, u64 *val) +{ +#ifdef CONFIG_X86_KERNEL_FINEIBT + const void *addr = (void *)(4 + *val); + union text_poke_insn text; + u32 insn; + + if (get_kernel_nofault(insn, addr) || !is_endbr(insn)) + return; + + if (get_kernel_nofault(text, addr+4) || text.opcode != SUB_INSN_OPCODE) + return; + + if (get_kernel_nofault(text, addr+11) || text.opcode != JE_INSN_OPCODE) + return; + + if (get_kernel_nofault(text, addr+13) || + text.opcode != CALL_INSN_OPCODE) + return; + + /* validate jmp.d32/call @ loc */ + if (WARN_ONCE(get_kernel_nofault(text, loc-1) || + (text.opcode != CALL_INSN_OPCODE && + text.opcode != JMP32_INSN_OPCODE), + "Unexpected code at: %pS\n", loc)) + return; + + DEBUGP("FineIBT fixed direct branch: %pS\n", addr); + + *val += 18; +#endif +} + static int __apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex, @@ -139,6 +174,7 @@ static int __apply_relocate_add(Elf64_Shdr *sechdrs, Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; Elf64_Sym *sym; void *loc; + int type; u64 val; DEBUGP("Applying relocate section %u to %u\n", @@ -153,13 +189,14 @@ static int __apply_relocate_add(Elf64_Shdr *sechdrs, sym = (Elf64_Sym *)sechdrs[symindex].sh_addr + ELF64_R_SYM(rel[i].r_info); + type = ELF64_R_TYPE(rel[i].r_info); + DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n", - (int)ELF64_R_TYPE(rel[i].r_info), - sym->st_value, rel[i].r_addend, (u64)loc); + type, sym->st_value, rel[i].r_addend, (u64)loc); val = sym->st_value + rel[i].r_addend; - switch (ELF64_R_TYPE(rel[i].r_info)) { + switch (type) { case R_X86_64_NONE: break; case R_X86_64_64: @@ -185,6 +222,8 @@ static int __apply_relocate_add(Elf64_Shdr *sechdrs, case R_X86_64_PLT32: if (*(u32 *)loc != 0) goto invalid_relocation; + if (type == R_X86_64_PLT32) + fineibt_branch_fix(loc, &val); val -= (u64)loc; write(loc, &val, 4); #if 0 diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 9717e6f6fb31..d8862673b416 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -230,6 +230,7 @@ objtool_args = \ $(if $(CONFIG_UNWINDER_ORC),orc generate,check) \ $(if $(part-of-module), --module) \ $(if $(CONFIG_X86_KERNEL_IBT), --lto --ibt) \ + $(if $(CONFIG_X86_KERNEL_FINEIBT), --fineibt) \ $(if $(CONFIG_FRAME_POINTER),, --no-fp) \ $(if $(CONFIG_GCOV_KERNEL)$(CONFIG_LTO_CLANG), --no-unreachable)\ $(if $(CONFIG_RETPOLINE), --retpoline) \ From patchwork Wed Apr 20 00:42:35 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joao Moreira X-Patchwork-Id: 12819536 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5A700C433F5 for ; Wed, 20 Apr 2022 00:43:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1358610AbiDTAqU (ORCPT ); Tue, 19 Apr 2022 20:46:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58740 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1358619AbiDTAqH (ORCPT ); Tue, 19 Apr 2022 20:46:07 -0400 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 544E0205D3; Tue, 19 Apr 2022 17:43:22 -0700 (PDT) Received: (Authenticated sender: joao@overdrivepizza.com) by mail.gandi.net (Postfix) with ESMTPSA id 166011BF203; Wed, 20 Apr 2022 00:43:14 +0000 (UTC) From: joao@overdrivepizza.com To: linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Cc: joao@overdrivepizza.com, peterz@infradead.org, jpoimboe@redhat.com, andrew.cooper3@citrix.com, keescook@chromium.org, samitolvanen@google.com, mark.rutland@arm.com, hjl.tools@gmail.com, alyssa.milburn@linux.intel.com, ndesaulniers@google.com, gabriel.gomes@linux.intel.com, rick.p.edgecombe@intel.com Subject: [RFC PATCH 05/11] x86/text-patching: Support FineIBT text-patching Date: Tue, 19 Apr 2022 17:42:35 -0700 Message-Id: <20220420004241.2093-6-joao@overdrivepizza.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220420004241.2093-1-joao@overdrivepizza.com> References: <20220420004241.2093-1-joao@overdrivepizza.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-hardening@vger.kernel.org From: Joao Moreira When patching a direct branch into text, consider that the target may have a FineIBT hash check sequence and then sum the respective offset to the branch target address if this is the case. This is needed to support static calls. Signed-off-by: Joao Moreira Tinkered-from-patches-by: Peter Zijlstra --- arch/x86/include/asm/text-patching.h | 92 +++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/text-patching.h b/arch/x86/include/asm/text-patching.h index d20ab0921480..a450761fae62 100644 --- a/arch/x86/include/asm/text-patching.h +++ b/arch/x86/include/asm/text-patching.h @@ -4,6 +4,7 @@ #include #include +#include #include struct paravirt_patch_site; @@ -66,6 +67,12 @@ extern void text_poke_finish(void); #define JMP8_INSN_SIZE 2 #define JMP8_INSN_OPCODE 0xEB +#define SUB_INSN_SIZE 7 +#define SUB_INSN_OPCODE 0x41 + +#define JE_INSN_SIZE 2 +#define JE_INSN_OPCODE 0x74 + #define DISP32_SIZE 4 static __always_inline int text_opcode_size(u8 opcode) @@ -96,6 +103,83 @@ union text_poke_insn { } __attribute__((packed)); }; +#ifdef CONFIG_X86_KERNEL_FINEIBT +#define FINEIBT_FIXUP 18 +// AFTER_FINEIBT = FINEIBT_FIXUP - ENDBR_LEN - XOR_LEN - JMP LEN +#define AFTER_FINEIBT FINEIBT_FIXUP - ENDBR_INSN_SIZE - 3 - 2 + +/// XXX: THIS IS *NOT* PROPERLY TESTED! +/// I did stumble on any scenario where this was needed while testing FineIBT, +/// Yet, I'm keeping this here for concept/future reference. - If we can't fix +/// the displacement, then the branch will always stumble on the FineIBT hash +/// check. To prevent that, patch the FineIBT hash check with nops. +static __always_inline +void bypass_fineibt_sequence(void *insn) { + static const char code[14] = { 0x4d, 0x31, 0xdb, 0xeb, AFTER_FINEIBT, + BYTES_NOP8, BYTES_NOP1 }; + if (unlikely(system_state == SYSTEM_BOOTING)) { + text_poke_early(insn + 4, code, 14); + text_poke_early(insn + 11, code, 14); + } + + text_poke_bp(insn + 4, code, 14, NULL); + text_poke_bp(insn + 11, code, 14, NULL); +} + +// Identify if the target address is a FineIBT instruction sequence, which +// should be: +// endbr +// sub $hash, %r11d +// je 1f +// call fineibt_handler (this will eventually be replaced with ud2) +// 1: +static __always_inline +bool __is_fineibt_sequence(const void *addr) { + union text_poke_insn text; + u32 insn; + + // the sequence starts with an endbr + if (get_kernel_nofault(insn, addr) || !(is_endbr(insn))) + return false; + + // then followed by a sub + if (get_kernel_nofault(text, addr+4) || text.opcode != SUB_INSN_OPCODE) + return false; + + // followed by a je + if (get_kernel_nofault(text, addr+11) || text.opcode != JE_INSN_OPCODE) + return false; + + // and finished with a call (which eventually will be an ud2) + if (get_kernel_nofault(text, addr+13) || + text.opcode != CALL_INSN_OPCODE) + return false; + + return true; +} + +// Verify if the branch target is a FineIBT sequence. If yes, fix the target +// to point right after the sequence, preventing crashes. +static __always_inline +void *__text_fix_fineibt_branch_target(const void *addr, void *dest, int size) { + bool fineibt; + s32 disp; + fineibt = __is_fineibt_sequence(dest); + if (!fineibt) + return dest; + + disp = (long) dest - (long) (addr + size) + FINEIBT_FIXUP; + + // if fineibt-fixed displacement doesn't fit as an operand, + // remove fineibt hash check from target. + if (size == 2 && ((disp >> 31) != (disp >> 7))) { + bypass_fineibt_sequence(dest); + return dest; + } + return dest + FINEIBT_FIXUP; +} +#endif + static __always_inline void __text_gen_insn(void *buf, u8 opcode, const void *addr, const void *dest, int size) { @@ -115,7 +199,13 @@ void __text_gen_insn(void *buf, u8 opcode, const void *addr, const void *dest, i insn->opcode = opcode; if (size > 1) { - insn->disp = (long)dest - (long)(addr + size); +#ifdef CONFIG_X86_KERNEL_FINEIBT + void *fineibt_dest = __text_fix_fineibt_branch_target(addr, + (void *) dest, size); + insn->disp = (long) fineibt_dest - (long) (addr + size); +#else + insn->disp = (long) dest - (long) (addr + size); +#endif if (size == 2) { /* * Ensure that for JMP8 the displacement From patchwork Wed Apr 20 00:42:36 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joao Moreira X-Patchwork-Id: 12819538 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AC041C43217 for ; Wed, 20 Apr 2022 00:43:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232990AbiDTAqU (ORCPT ); Tue, 19 Apr 2022 20:46:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58838 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1358624AbiDTAqT (ORCPT ); Tue, 19 Apr 2022 20:46:19 -0400 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8CF5C34BAC; Tue, 19 Apr 2022 17:43:28 -0700 (PDT) Received: (Authenticated sender: joao@overdrivepizza.com) by mail.gandi.net (Postfix) with ESMTPSA id B0F141BF206; Wed, 20 Apr 2022 00:43:21 +0000 (UTC) From: joao@overdrivepizza.com To: linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Cc: joao@overdrivepizza.com, peterz@infradead.org, jpoimboe@redhat.com, andrew.cooper3@citrix.com, keescook@chromium.org, samitolvanen@google.com, mark.rutland@arm.com, hjl.tools@gmail.com, alyssa.milburn@linux.intel.com, ndesaulniers@google.com, gabriel.gomes@linux.intel.com, rick.p.edgecombe@intel.com Subject: [RFC PATCH 06/11] x86/bpf: Support FineIBT Date: Tue, 19 Apr 2022 17:42:36 -0700 Message-Id: <20220420004241.2093-7-joao@overdrivepizza.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220420004241.2093-1-joao@overdrivepizza.com> References: <20220420004241.2093-1-joao@overdrivepizza.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-hardening@vger.kernel.org From: Joao Moreira BPF jitted code calls helper functions that are in the core and contain a FineIBT hash check sequence in their prologue. Make BPF jit capable of identifying FineIBT sequences when emitting calls and properly sum the offset to bypass it when emitting calls. Signed-off-by: Joao Moreira Tinkered-from-patches-by: Peter Zijlstra --- arch/x86/net/bpf_jit_comp.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 16b6efacf7c6..e0c82174a075 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -330,13 +330,44 @@ static int emit_patch(u8 **pprog, void *func, void *ip, u8 opcode) return 0; } +static inline bool skip_fineibt_sequence(void *func) +{ + const void *addr = (void *) func; + union text_poke_insn text; + u32 insn; + + if ((get_kernel_nofault(insn, addr)) || + (!is_endbr(insn))) + return false; + + if ((get_kernel_nofault(text, addr+4)) || + (text.opcode != SUB_INSN_OPCODE)) + return false; + + if ((get_kernel_nofault(text, addr+11)) || + (text.opcode != JE_INSN_OPCODE)) + return false; + + if ((get_kernel_nofault(text, addr+13)) || + (text.opcode != CALL_INSN_OPCODE)) + return false; + + return true; +} + static int emit_call(u8 **pprog, void *func, void *ip) { +#ifdef CONFIG_X86_KERNEL_FINEIBT + if(skip_fineibt_sequence(func)) func = func + FINEIBT_FIXUP; +#endif return emit_patch(pprog, func, ip, 0xE8); } static int emit_jump(u8 **pprog, void *func, void *ip) { +#ifdef CONFIG_X86_KERNEL_FINEIBT + if(skip_fineibt_sequence(func)) func = func + FINEIBT_FIXUP; +#endif return emit_patch(pprog, func, ip, 0xE9); } From patchwork Wed Apr 20 00:42:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joao Moreira X-Patchwork-Id: 12819537 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9CB12C4332F for ; Wed, 20 Apr 2022 00:43:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1358627AbiDTAqU (ORCPT ); Tue, 19 Apr 2022 20:46:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58796 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1358628AbiDTAqT (ORCPT ); Tue, 19 Apr 2022 20:46:19 -0400 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6B3C82C117; Tue, 19 Apr 2022 17:43:34 -0700 (PDT) Received: (Authenticated sender: joao@overdrivepizza.com) by mail.gandi.net (Postfix) with ESMTPSA id E24A91BF205; Wed, 20 Apr 2022 00:43:27 +0000 (UTC) From: joao@overdrivepizza.com To: linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Cc: joao@overdrivepizza.com, peterz@infradead.org, jpoimboe@redhat.com, andrew.cooper3@citrix.com, keescook@chromium.org, samitolvanen@google.com, mark.rutland@arm.com, hjl.tools@gmail.com, alyssa.milburn@linux.intel.com, ndesaulniers@google.com, gabriel.gomes@linux.intel.com, rick.p.edgecombe@intel.com Subject: [RFC PATCH 07/11] x86/lib: Prevent UACCESS call warning from objtool Date: Tue, 19 Apr 2022 17:42:37 -0700 Message-Id: <20220420004241.2093-8-joao@overdrivepizza.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220420004241.2093-1-joao@overdrivepizza.com> References: <20220420004241.2093-1-joao@overdrivepizza.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-hardening@vger.kernel.org From: Joao Moreira Objtool emits a warning whenever it finds a call that may happen with UACCESS enabled. Prevent this b not emitting calls to the __fineibt_handler in such circumstances, making the function coarse-grained. Signed-off-by: Joao Moreira --- arch/x86/lib/copy_mc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/lib/copy_mc.c b/arch/x86/lib/copy_mc.c index 80efd45a7761..554e6c6ecea2 100644 --- a/arch/x86/lib/copy_mc.c +++ b/arch/x86/lib/copy_mc.c @@ -22,7 +22,7 @@ void enable_copy_mc_fragile(void) * Similar to copy_user_handle_tail, probe for the write fault point, or * source exception point. */ -__visible notrace unsigned long +__visible notrace unsigned long __coarseendbr copy_mc_fragile_handle_tail(char *to, char *from, unsigned len) { for (; len; --len, to++, from++) From patchwork Wed Apr 20 00:42:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joao Moreira X-Patchwork-Id: 12819539 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 94F2BC433EF for ; Wed, 20 Apr 2022 00:43:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1358641AbiDTAq3 (ORCPT ); Tue, 19 Apr 2022 20:46:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58908 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1358642AbiDTAq0 (ORCPT ); Tue, 19 Apr 2022 20:46:26 -0400 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C7D1E17A93; Tue, 19 Apr 2022 17:43:41 -0700 (PDT) Received: (Authenticated sender: joao@overdrivepizza.com) by mail.gandi.net (Postfix) with ESMTPSA id BFA7F1BF206; Wed, 20 Apr 2022 00:43:33 +0000 (UTC) From: joao@overdrivepizza.com To: linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Cc: joao@overdrivepizza.com, peterz@infradead.org, jpoimboe@redhat.com, andrew.cooper3@citrix.com, keescook@chromium.org, samitolvanen@google.com, mark.rutland@arm.com, hjl.tools@gmail.com, alyssa.milburn@linux.intel.com, ndesaulniers@google.com, gabriel.gomes@linux.intel.com, rick.p.edgecombe@intel.com Subject: [RFC PATCH 08/11] x86/ibt: Add CET_TEST module for IBT testing Date: Tue, 19 Apr 2022 17:42:38 -0700 Message-Id: <20220420004241.2093-9-joao@overdrivepizza.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220420004241.2093-1-joao@overdrivepizza.com> References: <20220420004241.2093-1-joao@overdrivepizza.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-hardening@vger.kernel.org From: Joao Moreira Add a kernel module that violates IBT policy on load, triggering a control protection fault and makes the enforcement visible. Signed-off-by: Joao Moreira Tinkered-from-work-by: Alyssa Milburn --- arch/x86/Kconfig.debug | 5 +++++ arch/x86/kernel/Makefile | 1 + arch/x86/kernel/cet_test.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 arch/x86/kernel/cet_test.c diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index d3a6f74a94bd..d2463dd912c1 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -279,3 +279,8 @@ endchoice config FRAME_POINTER depends on !UNWINDER_ORC && !UNWINDER_GUESS bool + +config X86_CET_TEST + depends on m + depends on X86_KERNEL_IBT + tristate "in-kernel CET testing module" diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index cb947569e9d8..a82bcd14bd40 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -149,6 +149,7 @@ obj-$(CONFIG_UNWINDER_GUESS) += unwind_guess.o obj-$(CONFIG_AMD_MEM_ENCRYPT) += sev.o obj-$(CONFIG_X86_KERNEL_FINEIBT) += fineibt.o +obj-$(CONFIG_X86_CET_TEST) += cet_test.o ### # 64 bit specific files diff --git a/arch/x86/kernel/cet_test.c b/arch/x86/kernel/cet_test.c new file mode 100644 index 000000000000..c48be8cbd0b5 --- /dev/null +++ b/arch/x86/kernel/cet_test.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include + +static int cet_test_init(void) +{ + pr_info("CET test, expect faults\n"); + + // FIXME: use register_die_notifier + + asm volatile( + "lea 1f(%%rip), %%rax\n" + "jmp *%%rax\n" + "nop\n" + "1:\n" + /* no endbranch */ + "nop\n" + :::"rax" + ); + return 0; +} + +static void cet_test_exit(void) +{ +} + +module_init(cet_test_init); +module_exit(cet_test_exit); + +MODULE_LICENSE("GPL v2"); From patchwork Wed Apr 20 00:42:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joao Moreira X-Patchwork-Id: 12819540 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0B9C0C433F5 for ; Wed, 20 Apr 2022 00:43:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233020AbiDTAqk (ORCPT ); Tue, 19 Apr 2022 20:46:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58978 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1358642AbiDTAqc (ORCPT ); Tue, 19 Apr 2022 20:46:32 -0400 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E2356205C5; Tue, 19 Apr 2022 17:43:47 -0700 (PDT) Received: (Authenticated sender: joao@overdrivepizza.com) by mail.gandi.net (Postfix) with ESMTPSA id 3106F1BF207; Wed, 20 Apr 2022 00:43:38 +0000 (UTC) From: joao@overdrivepizza.com To: linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Cc: joao@overdrivepizza.com, peterz@infradead.org, jpoimboe@redhat.com, andrew.cooper3@citrix.com, keescook@chromium.org, samitolvanen@google.com, mark.rutland@arm.com, hjl.tools@gmail.com, alyssa.milburn@linux.intel.com, ndesaulniers@google.com, gabriel.gomes@linux.intel.com, rick.p.edgecombe@intel.com Subject: [RFC PATCH 09/11] x86/FineIBT: Add FINEIBT_TEST module Date: Tue, 19 Apr 2022 17:42:39 -0700 Message-Id: <20220420004241.2093-10-joao@overdrivepizza.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220420004241.2093-1-joao@overdrivepizza.com> References: <20220420004241.2093-1-joao@overdrivepizza.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-hardening@vger.kernel.org From: Joao Moreira Adds a module that on load will call a function directly ensuring that FineIBT fixes for module relocations are working as expected. Next the module invokes another function indirectly, with a wrong hash into R11, causing a violation to be triggered (and the __fineibt_handler to be invoked). Signed-off-by: Joao Moreira --- arch/x86/Kconfig.debug | 5 +++++ arch/x86/kernel/Makefile | 1 + arch/x86/kernel/fineibt_test.c | 39 ++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 arch/x86/kernel/fineibt_test.c diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index d2463dd912c1..4a5617c2470d 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -284,3 +284,8 @@ config X86_CET_TEST depends on m depends on X86_KERNEL_IBT tristate "in-kernel CET testing module" + +config X86_FINEIBT_TEST + depends on m + depends on X86_KERNEL_FINEIBT + tristate "in-kernel FineIBT testing module" diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index a82bcd14bd40..5d7f39f3d909 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -150,6 +150,7 @@ obj-$(CONFIG_UNWINDER_GUESS) += unwind_guess.o obj-$(CONFIG_AMD_MEM_ENCRYPT) += sev.o obj-$(CONFIG_X86_KERNEL_FINEIBT) += fineibt.o obj-$(CONFIG_X86_CET_TEST) += cet_test.o +obj-$(CONFIG_X86_FINEIBT_TEST) += fineibt_test.o ### # 64 bit specific files diff --git a/arch/x86/kernel/fineibt_test.c b/arch/x86/kernel/fineibt_test.c new file mode 100644 index 000000000000..c8cbff6208f8 --- /dev/null +++ b/arch/x86/kernel/fineibt_test.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include + +void __fineibt_debug(void); + +void fineibt_foo(void) { + pr_info("FineIBT: dmesg should show a FineIBT violation message.\n"); +} + +void fineibt_bar(void) { + pr_info("FineIBT: this first one should run smoothly.\n"); +} + +static int fineibt_test_init(void) +{ + pr_info("FineIBT test\n"); + + __fineibt_debug(); + + asm volatile( + "call fineibt_bar\n" + "lea fineibt_foo(%%rip), %%rax\n" + "mov $0xdeadbeef, %%r11\n" + "call *%%rax\n" + /* this should trigger the handler because the hash is wrong */ + ::: "rax" + ); + return 0; +} + +static void fineibt_test_exit(void) +{ +} + +module_init(fineibt_test_init); +module_exit(fineibt_test_exit); + +MODULE_LICENSE("GPL v2"); From patchwork Wed Apr 20 00:42:40 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joao Moreira X-Patchwork-Id: 12819541 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 28C9AC433EF for ; Wed, 20 Apr 2022 00:43:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1358654AbiDTAqk (ORCPT ); Tue, 19 Apr 2022 20:46:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59028 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1358656AbiDTAqg (ORCPT ); Tue, 19 Apr 2022 20:46:36 -0400 X-Greylist: delayed 61 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Tue, 19 Apr 2022 17:43:52 PDT Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::228]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7F74E205D3; Tue, 19 Apr 2022 17:43:51 -0700 (PDT) Received: (Authenticated sender: joao@overdrivepizza.com) by mail.gandi.net (Postfix) with ESMTPSA id 5D5D51BF205; Wed, 20 Apr 2022 00:43:45 +0000 (UTC) From: joao@overdrivepizza.com To: linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Cc: joao@overdrivepizza.com, peterz@infradead.org, jpoimboe@redhat.com, andrew.cooper3@citrix.com, keescook@chromium.org, samitolvanen@google.com, mark.rutland@arm.com, hjl.tools@gmail.com, alyssa.milburn@linux.intel.com, ndesaulniers@google.com, gabriel.gomes@linux.intel.com, rick.p.edgecombe@intel.com Subject: [RFC PATCH 10/11] linux/interrupt: Fix prototype matching property Date: Tue, 19 Apr 2022 17:42:40 -0700 Message-Id: <20220420004241.2093-11-joao@overdrivepizza.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220420004241.2093-1-joao@overdrivepizza.com> References: <20220420004241.2093-1-joao@overdrivepizza.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-hardening@vger.kernel.org From: Joao Moreira Unions will make function pointers with different prototypes be used through the same call. This leads into the same call instruction being used for calling functions with different prototypes, making them unsuitable for prototype-based fine-grained CFI. Fix this CFI policy violation by removing the function pointer union in the tasklet struct. Signed-off-by: Joao Moreira --- include/linux/interrupt.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index f40754caaefa..8d5504b0f20b 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -650,10 +650,8 @@ struct tasklet_struct unsigned long state; atomic_t count; bool use_callback; - union { - void (*func)(unsigned long data); - void (*callback)(struct tasklet_struct *t); - }; + void (*func)(unsigned long data); + void (*callback)(struct tasklet_struct *t); unsigned long data; }; From patchwork Wed Apr 20 00:42:41 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joao Moreira X-Patchwork-Id: 12819542 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 785A5C433FE for ; Wed, 20 Apr 2022 00:44:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1358657AbiDTAqn (ORCPT ); Tue, 19 Apr 2022 20:46:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59066 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1358658AbiDTAqm (ORCPT ); Tue, 19 Apr 2022 20:46:42 -0400 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6617A17A93; Tue, 19 Apr 2022 17:43:57 -0700 (PDT) Received: (Authenticated sender: joao@overdrivepizza.com) by mail.gandi.net (Postfix) with ESMTPSA id 4D9F41BF206; Wed, 20 Apr 2022 00:43:50 +0000 (UTC) From: joao@overdrivepizza.com To: linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Cc: joao@overdrivepizza.com, peterz@infradead.org, jpoimboe@redhat.com, andrew.cooper3@citrix.com, keescook@chromium.org, samitolvanen@google.com, mark.rutland@arm.com, hjl.tools@gmail.com, alyssa.milburn@linux.intel.com, ndesaulniers@google.com, gabriel.gomes@linux.intel.com, rick.p.edgecombe@intel.com Subject: [RFC PATCH 11/11] driver/int3400_thermal: Fix prototype matching Date: Tue, 19 Apr 2022 17:42:41 -0700 Message-Id: <20220420004241.2093-12-joao@overdrivepizza.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220420004241.2093-1-joao@overdrivepizza.com> References: <20220420004241.2093-1-joao@overdrivepizza.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-hardening@vger.kernel.org From: Joao Moreira The function attr_dev_show directly invokes functions from drivers expecting an specific prototype. The driver for int3400_thermal implements the given show function using a different prototype than what is expected. This violates the prototype-based fine-grained CFI policy. Make the function prototype compliant and cast the respective assignement so it can be properly user together with fine-grained CFI. (FWIIW, there should be a less ugly patch for this, but I don't know enough about the touched source code). Signed-off-by: Joao Moreira --- .../thermal/intel/int340x_thermal/int3400_thermal.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c index 4954800b9850..4bd95a2016b7 100644 --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c @@ -311,12 +311,13 @@ static int int3400_thermal_get_uuids(struct int3400_thermal_priv *priv) return result; } -static ssize_t odvp_show(struct kobject *kobj, struct kobj_attribute *attr, +static ssize_t odvp_show(struct device *kobj, struct device_attribute *attr, char *buf) { + struct kobj_attribute *kattr = (struct kobj_attribute *) attr; struct odvp_attr *odvp_attr; - odvp_attr = container_of(attr, struct odvp_attr, attr); + odvp_attr = container_of(kattr, struct odvp_attr, attr); return sprintf(buf, "%d\n", odvp_attr->priv->odvp[odvp_attr->odvp]); } @@ -388,7 +389,10 @@ static int evaluate_odvp(struct int3400_thermal_priv *priv) goto out_err; } odvp->attr.attr.mode = 0444; - odvp->attr.show = odvp_show; + odvp->attr.show = (ssize_t (*) + (struct kobject *, + struct kobj_attribute *, + char *)) odvp_show; odvp->attr.store = NULL; ret = sysfs_create_file(&priv->pdev->dev.kobj, &odvp->attr.attr);