Received: by 2002:a25:ad19:0:0:0:0:0 with SMTP id y25csp9604365ybi; Wed, 10 Jul 2019 13:20:12 -0700 (PDT) X-Google-Smtp-Source: APXvYqzabB4ZzLXgKd/1vDyOpoZu6aMVGJ4hJOnFs3Eh/8rGAw0AJwQprIR49Pl2KdpI0Gtp7g/G X-Received: by 2002:a63:7b4d:: with SMTP id k13mr110548pgn.182.1562790012287; Wed, 10 Jul 2019 13:20:12 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1562790012; cv=none; d=google.com; s=arc-20160816; b=zRB1S9vSv9yprm3WZVaMV/BHUffp4RZVg0G5qsUvzmkqnABBtlqJhnSH4t/4VICHVH oMC+IlzNAuwKjVdWuPrM+u0gAwN54rsNWTl1/7LCMdAARWL8Ld70+IoNkDpzl4H2XRWO Ik1GW8G0HQw3JUamxOsK2St0J5/Vi9/DJpYKsakK7DkJK8oAFd+PnYOQY77oaBZEZFMO q3Tc7BipL2BIfoB7E6hm2ZJLBP4uKtD43oX4aNuAElyLRmEb3UN0j2NsfJJRYmNaVYv0 Gbsuk7vyTFZzW5qlLhsehzxxQpCX38OhfHoB/6y2r2K9qW++SOO11Wlv2xbuzifBP5pB 3zXA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-disposition :content-transfer-encoding:mime-version:robot-unsubscribe:robot-id :git-commit-id:subject:to:references:in-reply-to:reply-to:cc :message-id:from:date:dkim-signature:dkim-filter; bh=YfzqZzDBDKoKQ/r74H08P1FgxD7OY3xdUhs3xQ5xdEI=; b=rE/8h4y8F8sUMDsYxg8qlpmqLseFn3llV86YP9vtcYOeP8ozEsYsvmC6sJwRMTdOJD 9hr+OVVyyjhGfc2fZSr+FyXExvdVjJFyjrdhKlJQsPx577eK0wLZKilE5n3rvobm1C62 g+4aHho1xhAMuMWxw+Bt/jV6jFQXgHjIc0wqOnXVNH4xEPM8Iu3BAGmcPZSF9PUGxDVZ kahqYdfY6pSz2fhk7v3AzJx3ghIbtHMCwpsjG2/SKPBvamWcnU+P5XZ+w7KNGD4aebmI puSmkEjpj7LBBbxeT9RO4JKjIvJdCrQbWy/V3Lu2z6vSXeqLOTrFqzwKeTPhuVp38xmP U/1g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@zytor.com header.s=2019061801 header.b=cdsIMIze; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=zytor.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id p1si3303887pff.250.2019.07.10.13.19.56; Wed, 10 Jul 2019 13:20:12 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@zytor.com header.s=2019061801 header.b=cdsIMIze; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=zytor.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727659AbfGJUT1 (ORCPT + 99 others); Wed, 10 Jul 2019 16:19:27 -0400 Received: from terminus.zytor.com ([198.137.202.136]:41907 "EHLO terminus.zytor.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727291AbfGJUT1 (ORCPT ); Wed, 10 Jul 2019 16:19:27 -0400 Received: from terminus.zytor.com (localhost [127.0.0.1]) by terminus.zytor.com (8.15.2/8.15.2) with ESMTPS id x6AKJA1k2574137 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NO); Wed, 10 Jul 2019 13:19:10 -0700 DKIM-Filter: OpenDKIM Filter v2.11.0 terminus.zytor.com x6AKJA1k2574137 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zytor.com; s=2019061801; t=1562789951; bh=YfzqZzDBDKoKQ/r74H08P1FgxD7OY3xdUhs3xQ5xdEI=; h=Date:From:Cc:Reply-To:In-Reply-To:References:To:Subject:From; b=cdsIMIze/rzleDkLQOPS/oWKf8a9iN+qlj6FbDL0X4jsj3BvDd1T9bXMT+EHtELdC +cCQ2kqzF7o2TGHHfB6w9z2nBE9Vfv34IvnhlEkrbaTWaU+llKWDrf9AuKSJycOmLp mglsoAIIv75nFlJzIumXw6aB1Y2m2GrOVMqhPlatEiW6CQsvWk7iiT3bm4Y2jQsdQ/ k9/+fw98lt7eRw6YJFj79y5j8H2tmXbhpVQPgHoQSQ4VazTmHFNh+wutoxp8uHKVIu Vm14s+3FHUS6fUB9w3CWlYxMc8o3ivr+hsYB7bx0nJUbrR1EZz+rBj5OUJyWNiNzGp NzvfWkmsMigLA== Received: (from tipbot@localhost) by terminus.zytor.com (8.15.2/8.15.2/Submit) id x6AKJ9TL2574133; Wed, 10 Jul 2019 13:19:09 -0700 Date: Wed, 10 Jul 2019 13:19:09 -0700 X-Authentication-Warning: terminus.zytor.com: tipbot set sender to tipbot@zytor.com using -f From: tip-bot for Thomas Gleixner Message-ID: Cc: hpa@zytor.com, keescook@chromium.org, mingo@kernel.org, tglx@linutronix.de, xry111@mengyan1223.wang, linux-kernel@vger.kernel.org, peterz@infradead.org, torvalds@linux-foundation.org Reply-To: hpa@zytor.com, mingo@kernel.org, keescook@chromium.org, tglx@linutronix.de, xry111@mengyan1223.wang, linux-kernel@vger.kernel.org, peterz@infradead.org, torvalds@linux-foundation.org In-Reply-To: References: To: linux-tip-commits@vger.kernel.org Subject: [tip:x86/urgent] x86/asm: Move native_write_cr0/4() out of line Git-Commit-ID: 7652ac92018536eb807b6c2130100c85f1ba7e3b X-Mailer: tip-git-log-daemon Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=UTF-8 Content-Disposition: inline X-Spam-Status: No, score=-0.1 required=5.0 tests=ALL_TRUSTED,BAYES_00, DATE_IN_FUTURE_03_06,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU, DKIM_VALID_EF autolearn=no autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on terminus.zytor.com Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Commit-ID: 7652ac92018536eb807b6c2130100c85f1ba7e3b Gitweb: https://git.kernel.org/tip/7652ac92018536eb807b6c2130100c85f1ba7e3b Author: Thomas Gleixner AuthorDate: Wed, 10 Jul 2019 21:42:46 +0200 Committer: Thomas Gleixner CommitDate: Wed, 10 Jul 2019 22:15:05 +0200 x86/asm: Move native_write_cr0/4() out of line The pinning of sensitive CR0 and CR4 bits caused a boot crash when loading the kvm_intel module on a kernel compiled with CONFIG_PARAVIRT=n. The reason is that the static key which controls the pinning is marked RO after init. The kvm_intel module contains a CR4 write which requires to update the static key entry list. That obviously does not work when the key is in a RO section. With CONFIG_PARAVIRT enabled this does not happen because the CR4 write uses the paravirt indirection and the actual write function is built in. As the key is intended to be immutable after init, move native_write_cr0/4() out of line. While at it consolidate the update of the cr4 shadow variable and store the value right away when the pinning is initialized on a booting CPU. No point in reading it back 20 instructions later. This allows to confine the static key and the pinning variable to cpu/common and allows to mark them static. Fixes: 8dbec27a242c ("x86/asm: Pin sensitive CR0 bits") Fixes: 873d50d58f67 ("x86/asm: Pin sensitive CR4 bits") Reported-by: Linus Torvalds Reported-by: Xi Ruoyao Signed-off-by: Thomas Gleixner Tested-by: Xi Ruoyao Acked-by: Kees Cook Acked-by: Peter Zijlstra (Intel) Link: https://lkml.kernel.org/r/alpine.DEB.2.21.1907102140340.1758@nanos.tec.linutronix.de --- arch/x86/include/asm/processor.h | 1 + arch/x86/include/asm/special_insns.h | 41 +------------------- arch/x86/kernel/cpu/common.c | 72 ++++++++++++++++++++++++++++-------- arch/x86/kernel/smpboot.c | 14 +------ arch/x86/xen/smp_pv.c | 1 + 5 files changed, 61 insertions(+), 68 deletions(-) diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 3eab6ece52b4..6e0a3b43d027 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -741,6 +741,7 @@ extern void load_direct_gdt(int); extern void load_fixmap_gdt(int); extern void load_percpu_segment(int); extern void cpu_init(void); +extern void cr4_init(void); static inline unsigned long get_debugctlmsr(void) { diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h index b2e84d113f2a..219be88a59d2 100644 --- a/arch/x86/include/asm/special_insns.h +++ b/arch/x86/include/asm/special_insns.h @@ -18,9 +18,7 @@ */ extern unsigned long __force_order; -/* Starts false and gets enabled once CPU feature detection is done. */ -DECLARE_STATIC_KEY_FALSE(cr_pinning); -extern unsigned long cr4_pinned_bits; +void native_write_cr0(unsigned long val); static inline unsigned long native_read_cr0(void) { @@ -29,24 +27,6 @@ static inline unsigned long native_read_cr0(void) return val; } -static inline void native_write_cr0(unsigned long val) -{ - unsigned long bits_missing = 0; - -set_register: - asm volatile("mov %0,%%cr0": "+r" (val), "+m" (__force_order)); - - if (static_branch_likely(&cr_pinning)) { - if (unlikely((val & X86_CR0_WP) != X86_CR0_WP)) { - bits_missing = X86_CR0_WP; - val |= bits_missing; - goto set_register; - } - /* Warn after we've set the missing bits. */ - WARN_ONCE(bits_missing, "CR0 WP bit went missing!?\n"); - } -} - static inline unsigned long native_read_cr2(void) { unsigned long val; @@ -91,24 +71,7 @@ static inline unsigned long native_read_cr4(void) return val; } -static inline void native_write_cr4(unsigned long val) -{ - unsigned long bits_missing = 0; - -set_register: - asm volatile("mov %0,%%cr4": "+r" (val), "+m" (cr4_pinned_bits)); - - if (static_branch_likely(&cr_pinning)) { - if (unlikely((val & cr4_pinned_bits) != cr4_pinned_bits)) { - bits_missing = ~val & cr4_pinned_bits; - val |= bits_missing; - goto set_register; - } - /* Warn after we've set the missing bits. */ - WARN_ONCE(bits_missing, "CR4 bits went missing: %lx!?\n", - bits_missing); - } -} +void native_write_cr4(unsigned long val); #ifdef CONFIG_X86_64 static inline unsigned long native_read_cr8(void) diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 309b6b9b49d4..11472178e17f 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -366,10 +366,62 @@ out: cr4_clear_bits(X86_CR4_UMIP); } -DEFINE_STATIC_KEY_FALSE_RO(cr_pinning); -EXPORT_SYMBOL(cr_pinning); -unsigned long cr4_pinned_bits __ro_after_init; -EXPORT_SYMBOL(cr4_pinned_bits); +static DEFINE_STATIC_KEY_FALSE_RO(cr_pinning); +static unsigned long cr4_pinned_bits __ro_after_init; + +void native_write_cr0(unsigned long val) +{ + unsigned long bits_missing = 0; + +set_register: + asm volatile("mov %0,%%cr0": "+r" (val), "+m" (__force_order)); + + if (static_branch_likely(&cr_pinning)) { + if (unlikely((val & X86_CR0_WP) != X86_CR0_WP)) { + bits_missing = X86_CR0_WP; + val |= bits_missing; + goto set_register; + } + /* Warn after we've set the missing bits. */ + WARN_ONCE(bits_missing, "CR0 WP bit went missing!?\n"); + } +} +EXPORT_SYMBOL(native_write_cr0); + +void native_write_cr4(unsigned long val) +{ + unsigned long bits_missing = 0; + +set_register: + asm volatile("mov %0,%%cr4": "+r" (val), "+m" (cr4_pinned_bits)); + + if (static_branch_likely(&cr_pinning)) { + if (unlikely((val & cr4_pinned_bits) != cr4_pinned_bits)) { + bits_missing = ~val & cr4_pinned_bits; + val |= bits_missing; + goto set_register; + } + /* Warn after we've set the missing bits. */ + WARN_ONCE(bits_missing, "CR4 bits went missing: %lx!?\n", + bits_missing); + } +} +EXPORT_SYMBOL(native_write_cr4); + +void cr4_init(void) +{ + unsigned long cr4 = __read_cr4(); + + if (boot_cpu_has(X86_FEATURE_PCID)) + cr4 |= X86_CR4_PCIDE; + if (static_branch_likely(&cr_pinning)) + cr4 |= cr4_pinned_bits; + + __write_cr4(cr4); + + /* Initialize cr4 shadow for this CPU. */ + this_cpu_write(cpu_tlbstate.cr4, cr4); +} /* * Once CPU feature detection is finished (and boot params have been @@ -1723,12 +1775,6 @@ void cpu_init(void) wait_for_master_cpu(cpu); - /* - * Initialize the CR4 shadow before doing anything that could - * try to read it. - */ - cr4_init_shadow(); - if (cpu) load_ucode_ap(); @@ -1823,12 +1869,6 @@ void cpu_init(void) wait_for_master_cpu(cpu); - /* - * Initialize the CR4 shadow before doing anything that could - * try to read it. - */ - cr4_init_shadow(); - show_ucode_info_early(); pr_info("Initializing CPU#%d\n", cpu); diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index f78801114ee1..259d1d2be076 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -210,28 +210,16 @@ static int enable_start_cpu0; */ static void notrace start_secondary(void *unused) { - unsigned long cr4 = __read_cr4(); - /* * Don't put *anything* except direct CPU state initialization * before cpu_init(), SMP booting is too fragile that we want to * limit the things done here to the most necessary things. */ - if (boot_cpu_has(X86_FEATURE_PCID)) - cr4 |= X86_CR4_PCIDE; - if (static_branch_likely(&cr_pinning)) - cr4 |= cr4_pinned_bits; - - __write_cr4(cr4); + cr4_init(); #ifdef CONFIG_X86_32 /* switch away from the initial page table */ load_cr3(swapper_pg_dir); - /* - * Initialize the CR4 shadow before doing anything that could - * try to read it. - */ - cr4_init_shadow(); __flush_tlb_all(); #endif load_current_idt(); diff --git a/arch/x86/xen/smp_pv.c b/arch/x86/xen/smp_pv.c index 77d81c1a63e9..802ee5bba66c 100644 --- a/arch/x86/xen/smp_pv.c +++ b/arch/x86/xen/smp_pv.c @@ -58,6 +58,7 @@ static void cpu_bringup(void) { int cpu; + cr4_init(); cpu_init(); touch_softlockup_watchdog(); preempt_disable();