From patchwork Tue Sep 12 07:58:30 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Gleixner X-Patchwork-Id: 138015 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:9ecd:0:b0:3f2:4152:657d with SMTP id t13csp251481vqx; Tue, 12 Sep 2023 01:13:02 -0700 (PDT) X-Google-Smtp-Source: AGHT+IG2Yos7C5Nt7gUjq74KdiGVJopC99Mj+FsLLD9wER1hCXqRB4TN+FrrReqFi44jg9Ax0Ez4 X-Received: by 2002:a05:6a20:3ca1:b0:122:10f9:f635 with SMTP id b33-20020a056a203ca100b0012210f9f635mr12625431pzj.19.1694506382514; Tue, 12 Sep 2023 01:13:02 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1694506382; cv=none; d=google.com; s=arc-20160816; b=tEgD6syp7Bnpj9Y7ljLIhZpgh88KNhbdqNt7huXM+bVRt8VTfNWiwf5oLIZA0WWpBG zGf2hKwTk+r7Pcvx1W2qW2f0fYDRyufVYl01Pz/8zePsCj4+fkcII89K7BOc/5frxOVd /r5X1p0BiRppDWXlJ4LmzHr9VpcQRjn1XCMT+ay71D2uN3gkwyVCkMpUUm67obxyUtR3 mXVpjyXuQCCkN5xR29+IEbiwgThuq5Q8NbjgnChqTE1uzmmOyvcfEpgQ0oqoFUJ+h2ki yGj2+vd/nO0XrZPEV8kxQ6xeK8lDcA/ub2XP4biCQfZJvZ7CP9kRfjavGzXx79hnQaOy CI4g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:date:mime-version:references:subject:cc:to:from :dkim-signature:dkim-signature:message-id; bh=VdESLJN1UDe6KHq+3VNdkhAeyWMXP2vTFS4VMSOD8jo=; fh=u57tXYamzTrJA+Ht8n1u7SfTMptrQaIb6LVW+jsaYf4=; b=bEZEYHqhgFMwclZ1vwoERXx6+QTU4s5K6yr+9a9m3X3eEOTGyLYgaI7Pak86HB79Nx bra78y+GhU2pWQ1ObIJ4V5bvWBpXIyM+WDGu9pZT50z4qrtJLa26lIuyyrkuv4Gvj5eM xKG3i0Za6wmCFxQf8fOwFWyq7m08o+KeleGsiqWPWebjp1JaC/OVgh2O/CHKG9Dgl5ZQ bLeX6usNuCMjDHtJejUmRyJyailUKXC8+LHt0Jk/FAXRvlzkSklBQJIpmmCvNILwsy9H 9a2eyVo9/b+fHR1ySTamhWwZJkg6RuPcPWShAAUk8+RZKI1naG8/JrkOPzqvbVToEdKK BfDg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=YaLzRKQK; dkim=neutral (no key) header.i=@linutronix.de header.s=2020e; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:8 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Received: from fry.vger.email (fry.vger.email. [2620:137:e000::3:8]) by mx.google.com with ESMTPS id c11-20020a056a00248b00b0068a52819fd2si7858638pfv.331.2023.09.12.01.13.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 12 Sep 2023 01:13:02 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:8 as permitted sender) client-ip=2620:137:e000::3:8; Authentication-Results: mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=YaLzRKQK; dkim=neutral (no key) header.i=@linutronix.de header.s=2020e; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:8 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by fry.vger.email (Postfix) with ESMTP id 561B981167A6; Tue, 12 Sep 2023 01:01:48 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at fry.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232046AbjILIBh (ORCPT + 39 others); Tue, 12 Sep 2023 04:01:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49950 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231876AbjILIAG (ORCPT ); Tue, 12 Sep 2023 04:00:06 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 20EC52D58 for ; Tue, 12 Sep 2023 00:58:32 -0700 (PDT) Message-ID: <20230912065502.568284573@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1694505510; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=VdESLJN1UDe6KHq+3VNdkhAeyWMXP2vTFS4VMSOD8jo=; b=YaLzRKQK8+LTZpmgX3paV0GM/G1hHhtrG9N3KG8YaaNQs2KNWHVQE+0wEvHkfIi8lsAIEt x5Np+s61VMdQ5TxNy2GoqmWXM+lhEFTOKnID5KvJvHDLIVoH4SP9pXeXJl0nrAwjSWKpO+ cLjt8FU1BqcouG9gA5P5mxh7ofubs3JJ+sSVcLoLduyoCfEpPT7iXbyfgqG/tvChRy2TSS OtS4uxcz76tvaisuCHtMYFqM8PN6i9dWMvVpAtl57CWIj16PbZKHT0j8g5HwVGPNVH4krF 2QZVCYZRPykScAoZTHKk/MjjJbD00/5Qs7mjynKO3OUSY84+Sv6lALwYnrQxcQ== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1694505510; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=VdESLJN1UDe6KHq+3VNdkhAeyWMXP2vTFS4VMSOD8jo=; b=Cosagv9a1arZfw8X5ur0v7Q3gMaEvrlXcCDIrn4psoiXiQrJ+Z9CGOOJ+CZhZnEB4WKfzv 0SW5s+hrTDgba4Bw== From: Thomas Gleixner To: LKML Cc: x86@kernel.org, Borislav Petkov , "Chang S. Bae" , Arjan van de Ven , Nikolay Borisov Subject: [patch V3 29/30] x86/microcode: Prepare for minimal revision check References: <20230912065249.695681286@linutronix.de> MIME-Version: 1.0 Date: Tue, 12 Sep 2023 09:58:30 +0200 (CEST) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (fry.vger.email [0.0.0.0]); Tue, 12 Sep 2023 01:01:48 -0700 (PDT) X-Spam-Status: No, score=-0.9 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on fry.vger.email X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1776818724546019980 X-GMAIL-MSGID: 1776818724546019980 From: Thomas Gleixner Applying microcode late can be fatal for the running kernel when the update changes functionality which is in use already in a non-compatible way, e.g. by removing a CPUID bit. There is no way for admins which do not have access to the vendors deep technical support to decide whether late loading of such a microcode is safe or not. Intel has added a new field to the microcode header which tells the minimal microcode revision which is required to be active in the CPU in order to be safe. Provide infrastructure for handling this in the core code and a command line switch which allows to enforce it. If the update is considered safe the kernel is not tainted and the annoying warning message not emitted. If it's enforced and the currently loaded microcode revision is not safe for late loading then the load is aborted. Signed-off-by: Thomas Gleixner --- Documentation/admin-guide/kernel-parameters.txt | 5 ++++ arch/x86/Kconfig | 23 ++++++++++++++++++- arch/x86/kernel/cpu/microcode/amd.c | 3 ++ arch/x86/kernel/cpu/microcode/core.c | 29 ++++++++++++++++++------ arch/x86/kernel/cpu/microcode/intel.c | 3 ++ arch/x86/kernel/cpu/microcode/internal.h | 3 ++ 6 files changed, 58 insertions(+), 8 deletions(-) --- --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3275,6 +3275,11 @@ mga= [HW,DRM] + microcode.force_minrev= [X86] + Format: + Enable or disable the microcode minimal revision + enforcement for the runtime microcode loader. + min_addr=nn[KMG] [KNL,BOOT,IA-64] All physical memory below this physical address is ignored. --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1322,7 +1322,28 @@ config MICROCODE_LATE_LOADING is a tricky business and should be avoided if possible. Just the sequence of synchronizing all cores and SMT threads is one fragile dance which does not guarantee that cores might not softlock after the loading. Therefore, - use this at your own risk. Late loading taints the kernel too. + use this at your own risk. Late loading taints the kernel unless the + microcode header indicates that it is safe for late loading via the + minimal revision check. This minimal revision check can be enforced on + the kernel command line with "microcode.minrev=Y". + +config MICROCODE_LATE_FORCE_MINREV + bool "Enforce late microcode loading minimal revision check" + default n + depends on MICROCODE_LATE_LOADING + help + To prevent that users load microcode late which modifies already + in use features, newer microcodes have a minimum revision field + in the microcode header, which tells the kernel which minimum + revision must be active in the CPU to safely load that new microcode + late into the running system. If disabled the check will not + be enforced but the kernel will be tainted when the minimal + revision check fails. + + This minimal revision check can also be controlled via the + "microcode.minrev" parameter on the kernel command line. + + If unsure say Y. config X86_MSR tristate "/dev/cpu/*/msr - Model-specific register support" --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -900,6 +900,9 @@ static enum ucode_state request_microcod enum ucode_state ret = UCODE_NFOUND; const struct firmware *fw; + if (force_minrev) + return UCODE_NFOUND; + if (c->x86 >= 0x15) snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86); --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -46,6 +46,9 @@ static struct microcode_ops *microcode_ops; static bool dis_ucode_ldr = true; +bool force_minrev = IS_ENABLED(CONFIG_MICROCODE_LATE_FORCE_MINREV); +module_param(force_minrev, bool, S_IRUSR | S_IWUSR); + bool initrd_gone; /* @@ -558,15 +561,17 @@ static int ucode_load_cpus_stopped(void return 0; } -static int ucode_load_late_stop_cpus(void) +static int ucode_load_late_stop_cpus(bool is_safe) { unsigned int cpu, updated = 0, failed = 0, timedout = 0, siblings = 0; unsigned int nr_offl, offline = 0; int old_rev = boot_cpu_data.microcode; struct cpuinfo_x86 prev_info; - pr_err("Attempting late microcode loading - it is dangerous and taints the kernel.\n"); - pr_err("You should switch to early loading, if possible.\n"); + if (!is_safe) { + pr_err("Late microcode loading without minimal revision check.\n"); + pr_err("You should switch to early loading, if possible.\n"); + } atomic_set(&late_cpus_in, num_online_cpus()); atomic_set(&offline_in_nmi, 0); @@ -616,7 +621,9 @@ static int ucode_load_late_stop_cpus(voi return -EIO; } - add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK); + if (!is_safe || failed || timedout) + add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK); + pr_info("Microcode load: updated on %u primary CPUs with %u siblings\n", updated, siblings); if (failed || timedout) { pr_err("Microcode load incomplete. %u CPUs timed out or failed\n", @@ -710,9 +717,17 @@ static int ucode_load_late_locked(void) return -EBUSY; ret = microcode_ops->request_microcode_fw(0, µcode_pdev->dev); - if (ret != UCODE_NEW) - return ret == UCODE_NFOUND ? -ENOENT : -EBADFD; - return ucode_load_late_stop_cpus(); + + switch (ret) { + case UCODE_NEW: + case UCODE_NEW_SAFE: + break; + case UCODE_NFOUND: + return -ENOENT; + default: + return -EBADFD; + } + return ucode_load_late_stop_cpus(ret == UCODE_NEW_SAFE); } static ssize_t reload_store(struct device *dev, --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -470,6 +470,9 @@ static enum ucode_state read_ucode_intel unsigned int curr_mc_size = 0; u8 *new_mc = NULL, *mc = NULL; + if (force_minrev) + return UCODE_NFOUND; + while (iov_iter_count(iter)) { struct microcode_header_intel mc_header; unsigned int mc_size, data_size; --- a/arch/x86/kernel/cpu/microcode/internal.h +++ b/arch/x86/kernel/cpu/microcode/internal.h @@ -13,6 +13,7 @@ struct device; enum ucode_state { UCODE_OK = 0, UCODE_NEW, + UCODE_NEW_SAFE, UCODE_UPDATED, UCODE_NFOUND, UCODE_ERROR, @@ -36,6 +37,8 @@ struct microcode_ops { use_nmi : 1; }; +extern bool force_minrev; + extern struct ucode_cpu_info ucode_cpu_info[]; struct cpio_data find_microcode_in_initrd(const char *path);