Received: by 2002:a05:6a10:22f:0:0:0:0 with SMTP id 15csp4109154pxk; Tue, 29 Sep 2020 14:48:24 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwep0Ub6CCvSW4lWormYktQX7LsHvIby6AmcFnkAYKkGp80oTPl5f0SyqeKJiAu5whEclNh X-Received: by 2002:a50:fe82:: with SMTP id d2mr5397593edt.86.1601416103743; Tue, 29 Sep 2020 14:48:23 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1601416103; cv=none; d=google.com; s=arc-20160816; b=AyTg+uJIDw9uzNowaML6M3m62/etpOj3Ol9zsKzS2wc6osrSCMVB0dmF+ed6t7xk3R nwG2uTjmNLKYQdlflm47UaLO6yTYWfJkRpXrzkMSR2cv687NQOzA/X1X20lQ8XA4j+Td Xp1wmXtJDk6v4pKxoBqUbLat+4C+w/vQm5Vf4D8Cq8TwE08pln+qpN/ZO6jVqFvPSgWy AYeBRq/cpN/nou4stDqrnKbkqGIT48mMXRC64yP8KDdHxVksSd4WrJ5LxIg1DzPDCxEf DVFoSh1vSmS+gFh66Uh6hXodV2ysFr4Df4v3paxHTDEvAMp9kOxXte/+QfwsUug2v982 Nu8g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:references:mime-version :message-id:in-reply-to:date:sender:dkim-signature; bh=UwKpg/5Z1qItAC/Ii0Bxjjb/I6thanoVy1WalWl9wp0=; b=PsHJ+ang4Rv6RumR12dQaKeI2DuduELSKySvDv8KtbJH68CVnbm/UGS64RY+n/1B6o pPViePT6Dpg75xVkzIKwyMNRolUEwMA5etWdWruCFfDE4rkpv5rEHzFL+UrANCX4oR9E Op8qDyApaD+lgakUtz9+LhzoqmrdJCWKXJZx489xwAyDHvB2QI80sObqSZTaZ2Qe6QXX vCyT4uYC3omawT5ZmK7DH4+sYJRn94uAMf177QwW6eZhXaqpN8V0Pmy9vDnlgD3DgB35 YvRgLiBAzplcoxGIAvp5hQN4Y+NDRHmfjknqH6ia2UZ0Udv+6QIy+sSEpkNnNwRrCkCa KX4A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=dLCw4eUR; 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=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id n10si3632648ejk.73.2020.09.29.14.48.00; Tue, 29 Sep 2020 14:48:23 -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=@google.com header.s=20161025 header.b=dLCw4eUR; 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=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728535AbgI2Vqu (ORCPT + 99 others); Tue, 29 Sep 2020 17:46:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48186 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728363AbgI2Vqk (ORCPT ); Tue, 29 Sep 2020 17:46:40 -0400 Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C5145C0613D7 for ; Tue, 29 Sep 2020 14:46:37 -0700 (PDT) Received: by mail-yb1-xb4a.google.com with SMTP id d143so6380128ybh.11 for ; Tue, 29 Sep 2020 14:46:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=UwKpg/5Z1qItAC/Ii0Bxjjb/I6thanoVy1WalWl9wp0=; b=dLCw4eURXFRjR4Z7tvmtmTL9xfiqurK7wcWM0l8PBjIbwvPCbJmmO+SJ2UZ1IXD8o+ XJWKvdRewP8LtINFtafpdTbGvf/Jf27C8Az1rl379bRaV2g6/1JHsqbdyp2zhzaczdit pv3dBDhtBx/5mhjLN5bVfqmDembsU8soCZOn5biYM7VYXU0VfErs3C8vvWZNdG8yE7lF PvSgLFZb7n6a8779ReVcu/tOZrkV+qe8dtuDW+M98yXbMpIMpcvDLOIhdBTOsmvuxBIY A7ugbpeW3avPmVIESZJYRXmAeCXzc3jwBrnHxbDeQp3TYLVV3l5KxApvYSbHLLNKBEP4 croQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=UwKpg/5Z1qItAC/Ii0Bxjjb/I6thanoVy1WalWl9wp0=; b=eMYndcoHzdYnFGVjqRYGmLjgH5h5tpCH/EzMbyIfyDD4fqHQozMftk1j/twCcKiFNO 9QPm+DSW1GVRwXlPQY3cYfzNNt0sSCYrtA2pRpKpyclQgOCAVr9480DyDtWLk+Xn+OLT Q/dBitYh2lVSpAzMn8f8cKyPDr9PKkdvmNOAYyOZ2kHFcTiJKuYx3bmaHfJvNLrO59w0 TrHKsQsyZazBQ3+qOCBVapJrccjMNx8Jioe+eKDaxkDjT/wrbNdFDU5KCh/Ap0trkljk 81lFuGCGNQdNp55dGEsGoiTbWqcags96QmFSLHwv2M4lVjjKhvnf0b8ytthXuXPNKWEO 0NIw== X-Gm-Message-State: AOAM533Ahxg4JvDj22ya30hfK5sKkznt1/93WuwYRaKUTcOiQJiuZwye CKoiTamFwfRWJR1VLVNG17f+SchuAGAzNFHgbU0= Sender: "samitolvanen via sendgmr" X-Received: from samitolvanen1.mtv.corp.google.com ([2620:15c:201:2:f693:9fff:fef4:1b6d]) (user=samitolvanen job=sendgmr) by 2002:a25:4c89:: with SMTP id z131mr8996298yba.256.1601415996927; Tue, 29 Sep 2020 14:46:36 -0700 (PDT) Date: Tue, 29 Sep 2020 14:46:04 -0700 In-Reply-To: <20200929214631.3516445-1-samitolvanen@google.com> Message-Id: <20200929214631.3516445-3-samitolvanen@google.com> Mime-Version: 1.0 References: <20200929214631.3516445-1-samitolvanen@google.com> X-Mailer: git-send-email 2.28.0.709.gb0816b6eb0-goog Subject: [PATCH v4 02/29] x86/asm: Replace __force_order with memory clobber From: Sami Tolvanen To: Masahiro Yamada , Will Deacon , Steven Rostedt Cc: Peter Zijlstra , Greg Kroah-Hartman , "Paul E. McKenney" , Kees Cook , Nick Desaulniers , clang-built-linux@googlegroups.com, kernel-hardening@lists.openwall.com, linux-arch@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, x86@kernel.org, Arvind Sankar Content-Type: text/plain; charset="UTF-8" Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Arvind Sankar 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 Tested-by: Nathan Chancellor Tested-by: Sedat Dilek Reviewed-by: Kees Cook Reviewed-by: Miguel Ojeda Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82602 Link: https://lore.kernel.org/lkml/20200527135329.1172644-1-arnd@arndb.de/ --- 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 c8862696a47b..7d0394f4ebf9 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 59a3e13204c3..d6e3bb9363d2 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 c5d6f17d9b9d..178499f90366 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)) { -- 2.28.0.709.gb0816b6eb0-goog