Received: by 2002:a05:6a10:6744:0:0:0:0 with SMTP id w4csp4689311pxu; Tue, 13 Oct 2020 05:01:41 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzKX2gI2o+e3uxrmxeaaxPGED9V5oUKr9n5hET1pK5frG55xXlNwH4P2ZQt9N3vLrqPYlDZ X-Received: by 2002:adf:e289:: with SMTP id v9mr35400323wri.14.1602590501376; Tue, 13 Oct 2020 05:01:41 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1602590501; cv=none; d=google.com; s=arc-20160816; b=ec2Lp8bFpe9o/RCZbG2xHlAX9d/IKFkw12+901/Trpizok79jxugch6NT+cJDE5Ct8 bGP7mjzfpPOf8cTnCWg2ZrnR19X11PlrFqR/Zg8ogujxSQymNXDb9mjgzan/hmre4c9Y JC2bcN83bf3QkDbmnWpS01g/vHgJDrFXSn/WPfQPDzXyopcOLY4Kusdx3AkSfQbqzOwm NmdDFz7PSqtjzcrmUraKqpTy3ftuPKShFebpOkXgi9XaJ8TZkTP5VsExkT7TdTLYU2hC Ud5YK1/7nqM66vRr3P0GZfLskkViw/F6gj2v04ZagEqy5KNz/McK2jCcDgg6Xsm0GYxn 50Zw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:robot-unsubscribe :robot-id:message-id:mime-version:references:in-reply-to:cc:subject :to:reply-to:sender:from:dkim-signature:dkim-signature:date; bh=9qI7IVgRwl0GxwjuHeeuZqgKMCTdvbHG4mHrEbESKQA=; b=wISGqIPK3w3N8S5Fkx4uy2FcPwW79qpKSXLkF/Cne3ttLlw+6NEwnDneCPKVapDgWu LI4MH6SYgw/P5SybPpPyfDIDf1FcTbghjCmtTy/yvOxXOn0XfJTM3zqgJKyO7MkRvozI F++oIe4nWUB6DnF5j5BGB2OQN0f4qJd9YJK+vl3RLmYxg0ppW3XanDmmi9Qmw0s+AbGy qOLqq1zpP0hmDaw5A7+tNiVmwTOWHUAUr/JjEVzefo4MqNvcckZcXtcsoCkyUnwTBjhJ 52qdbUre8j4OvDGd+kl3mp/Q1Y1XRvYsET0ODj6jHR9h3uww+IgcGTEzb0fe82z6KXqE EykQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=PDvFKaNu; dkim=neutral (no key) header.i=@linutronix.de; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id p15si14231888ejm.293.2020.10.13.05.01.16; Tue, 13 Oct 2020 05:01:41 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=PDvFKaNu; dkim=neutral (no key) header.i=@linutronix.de; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2391509AbgJMJa6 (ORCPT + 99 others); Tue, 13 Oct 2020 05:30:58 -0400 Received: from Galois.linutronix.de ([193.142.43.55]:50756 "EHLO galois.linutronix.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390610AbgJMJa5 (ORCPT ); Tue, 13 Oct 2020 05:30:57 -0400 Date: Tue, 13 Oct 2020 09:30:52 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1602581453; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9qI7IVgRwl0GxwjuHeeuZqgKMCTdvbHG4mHrEbESKQA=; b=PDvFKaNumCt4SksJS5j1nwq9IdyT1/951jUOOWcNLXO0VDgO2YnAsmSwVBTh4DoVHYciNh T2wO6KD7NIPtw3F+Qa7MTDolUnR2MokZHOO7zhYucZj6Fzhaq8L7LhTSkuixsMGnx+AiK7 M3pwKDwgj1Shjm5RLEydqaGGffpzaKH1irJcsTov93OzrIkcPDwrZFqxAqSl5o6PMlK+4B 278PyfqT7N+zdmLsSFbECnPTZ+URpJKddKnGgF1bI7/Nak6/xZDMOy+5VBJ9RxSrXibmNG CYcub6nDIZ+L0UE9h0kA+/L+rp000gXp8CqOFvhl80lRcmSDT+tJ3GjN5tSuEg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1602581453; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9qI7IVgRwl0GxwjuHeeuZqgKMCTdvbHG4mHrEbESKQA=; b=DIirML3btFhQXHtLll+Z/db0VU82RC9UeW2k4CY6QEv4cLOs3w2eaMq9Yc4i44wi1OLbsW Ean60Zu67f+c3sBg== From: "tip-bot2 for Arvind Sankar" Sender: tip-bot2@linutronix.de Reply-to: linux-kernel@vger.kernel.org To: linux-tip-commits@vger.kernel.org Subject: [tip: x86/asm] x86/asm: Replace __force_order with a memory clobber Cc: Arvind Sankar , Borislav Petkov , Kees Cook , Miguel Ojeda , Nathan Chancellor , Sedat Dilek , x86 , LKML In-Reply-To: <20200902232152.3709896-1-nivedita@alum.mit.edu> References: <20200902232152.3709896-1-nivedita@alum.mit.edu> MIME-Version: 1.0 Message-ID: <160258145262.7002.8053536940451102515.tip-bot2@tip-bot2> Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The following commit has been merged into the x86/asm branch of tip: Commit-ID: 3e626682046e30282979f7d71e054cd4c00069a7 Gitweb: https://git.kernel.org/tip/3e626682046e30282979f7d71e054cd4c00069a7 Author: Arvind Sankar AuthorDate: Wed, 02 Sep 2020 19:21:52 -04:00 Committer: Borislav Petkov CommitterDate: Tue, 13 Oct 2020 11:23:15 +02:00 x86/asm: Replace __force_order with a memory clobber The CRn accessor functions use __force_order as a dummy operand to prevent the compiler from reordering CRn reads/writes with respect to each other. The fact that the asm is volatile should be enough to prevent this: volatile asm statements should be executed in program order. However GCC 4.9.x and 5.x have a bug that might result in reordering. This was fixed in 8.1, 7.3 and 6.5. Versions prior to these, including 5.x and 4.9.x, may reorder volatile asm statements with respect to each other. There are some issues with __force_order as implemented: - It is used only as an input operand for the write functions, and hence doesn't do anything additional to prevent reordering writes. - It allows memory accesses to be cached/reordered across write functions, but CRn writes affect the semantics of memory accesses, so this could be dangerous. - __force_order is not actually defined in the kernel proper, but the LLVM toolchain can in some cases require a definition: LLVM (as well as GCC 4.9) requires it for PIE code, which is why the compressed kernel has a definition, but also the clang integrated assembler may consider the address of __force_order to be significant, resulting in a reference that requires a definition. Fix this by: - Using a memory clobber for the write functions to additionally prevent caching/reordering memory accesses across CRn writes. - Using a dummy input operand with an arbitrary constant address for the read functions, instead of a global variable. This will prevent reads from being reordered across writes, while allowing memory loads to be cached/reordered across CRn reads, which should be safe. Signed-off-by: Arvind Sankar Signed-off-by: Borislav Petkov Reviewed-by: Kees Cook Reviewed-by: Miguel Ojeda Tested-by: Nathan Chancellor Tested-by: Sedat Dilek Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82602 Link: https://lore.kernel.org/lkml/20200527135329.1172644-1-arnd@arndb.de/ Link: https://lkml.kernel.org/r/20200902232152.3709896-1-nivedita@alum.mit.edu --- arch/x86/boot/compressed/pgtable_64.c | 9 +-------- arch/x86/include/asm/special_insns.h | 28 +++++++++++++------------- arch/x86/kernel/cpu/common.c | 4 ++-- 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/arch/x86/boot/compressed/pgtable_64.c b/arch/x86/boot/compressed/pgtable_64.c index c886269..7d0394f 100644 --- a/arch/x86/boot/compressed/pgtable_64.c +++ b/arch/x86/boot/compressed/pgtable_64.c @@ -5,15 +5,6 @@ #include "pgtable.h" #include "../string.h" -/* - * __force_order is used by special_insns.h asm code to force instruction - * serialization. - * - * It is not referenced from the code, but GCC < 5 with -fPIE would fail - * due to an undefined symbol. Define it to make these ancient GCCs work. - */ -unsigned long __force_order; - #define BIOS_START_MIN 0x20000U /* 128K, less than this is insane */ #define BIOS_START_MAX 0x9f000U /* 640K, absolute maximum */ diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h index 59a3e13..d6e3bb9 100644 --- a/arch/x86/include/asm/special_insns.h +++ b/arch/x86/include/asm/special_insns.h @@ -11,45 +11,47 @@ #include /* - * Volatile isn't enough to prevent the compiler from reordering the - * read/write functions for the control registers and messing everything up. - * A memory clobber would solve the problem, but would prevent reordering of - * all loads stores around it, which can hurt performance. Solution is to - * use a variable and mimic reads and writes to it to enforce serialization + * The compiler should not reorder volatile asm statements with respect to each + * other: they should execute in program order. However GCC 4.9.x and 5.x have + * a bug (which was fixed in 8.1, 7.3 and 6.5) where they might reorder + * volatile asm. The write functions are not affected since they have memory + * clobbers preventing reordering. To prevent reads from being reordered with + * respect to writes, use a dummy memory operand. */ -extern unsigned long __force_order; + +#define __FORCE_ORDER "m"(*(unsigned int *)0x1000UL) void native_write_cr0(unsigned long val); static inline unsigned long native_read_cr0(void) { unsigned long val; - asm volatile("mov %%cr0,%0\n\t" : "=r" (val), "=m" (__force_order)); + asm volatile("mov %%cr0,%0\n\t" : "=r" (val) : __FORCE_ORDER); return val; } static __always_inline unsigned long native_read_cr2(void) { unsigned long val; - asm volatile("mov %%cr2,%0\n\t" : "=r" (val), "=m" (__force_order)); + asm volatile("mov %%cr2,%0\n\t" : "=r" (val) : __FORCE_ORDER); return val; } static __always_inline void native_write_cr2(unsigned long val) { - asm volatile("mov %0,%%cr2": : "r" (val), "m" (__force_order)); + asm volatile("mov %0,%%cr2": : "r" (val) : "memory"); } static inline unsigned long __native_read_cr3(void) { unsigned long val; - asm volatile("mov %%cr3,%0\n\t" : "=r" (val), "=m" (__force_order)); + asm volatile("mov %%cr3,%0\n\t" : "=r" (val) : __FORCE_ORDER); return val; } static inline void native_write_cr3(unsigned long val) { - asm volatile("mov %0,%%cr3": : "r" (val), "m" (__force_order)); + asm volatile("mov %0,%%cr3": : "r" (val) : "memory"); } static inline unsigned long native_read_cr4(void) @@ -64,10 +66,10 @@ static inline unsigned long native_read_cr4(void) asm volatile("1: mov %%cr4, %0\n" "2:\n" _ASM_EXTABLE(1b, 2b) - : "=r" (val), "=m" (__force_order) : "0" (0)); + : "=r" (val) : "0" (0), __FORCE_ORDER); #else /* CR4 always exists on x86_64. */ - asm volatile("mov %%cr4,%0\n\t" : "=r" (val), "=m" (__force_order)); + asm volatile("mov %%cr4,%0\n\t" : "=r" (val) : __FORCE_ORDER); #endif return val; } diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index c5d6f17..178499f 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -359,7 +359,7 @@ void native_write_cr0(unsigned long val) unsigned long bits_missing = 0; set_register: - asm volatile("mov %0,%%cr0": "+r" (val), "+m" (__force_order)); + asm volatile("mov %0,%%cr0": "+r" (val) : : "memory"); if (static_branch_likely(&cr_pinning)) { if (unlikely((val & X86_CR0_WP) != X86_CR0_WP)) { @@ -378,7 +378,7 @@ void native_write_cr4(unsigned long val) unsigned long bits_changed = 0; set_register: - asm volatile("mov %0,%%cr4": "+r" (val), "+m" (cr4_pinned_bits)); + asm volatile("mov %0,%%cr4": "+r" (val) : : "memory"); if (static_branch_likely(&cr_pinning)) { if (unlikely((val & cr4_pinned_mask) != cr4_pinned_bits)) {