Received: by 2002:a6b:500f:0:0:0:0:0 with SMTP id e15csp130867iob; Tue, 17 May 2022 21:16:08 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwlZKAIti05hFpJlZYkhWbM2AuKIdmNCC1sXE1jKDcNBtVRnmQQtSPHsYXrm9xAELCeh8Ja X-Received: by 2002:a17:902:d5cb:b0:161:6a34:37ac with SMTP id g11-20020a170902d5cb00b001616a3437acmr15001160plh.83.1652847367956; Tue, 17 May 2022 21:16:07 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1652847367; cv=none; d=google.com; s=arc-20160816; b=mBm0Y8jXH15cdioBaB9aPAXmLkROHjBobYWYBwD/3W7+IEVorh2uRP/HABVyo4CExm glBsbadZwcj0y6CjmZ3bW7BEEraApMRIybDTmB2GO1Ab7FzmjI85HBbWzqsgM2iHS0dd UT3HSTAIEjNb+Za9cgFxrmA/O8b3VWe359FnbiAzZqNbSwx2ni5n9bKR/YHHaUdVmhS4 BcyXxfik2UH0sOzDjXBI9uLRuYXgEK+ouYeZNwtUaUhsNXi55P0Zd9EEOYcNSWNE2cUJ R9zAn2uZOeQWQbwCOty1/q0HE9GtiBNoNVeBX9F/UtqMyHwvE8jXHSDf+CDUvmK56jel P+0Q== 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:reply-to:dkim-signature; bh=rR9QT3FVOBG/jORwlMjkzEP1wf5ezoAh1SN5/FtrVoY=; b=eSBr2MAqkrHODG488K9ZC4XrW/AWOkhXJEdWR1OYQzm6X6d7ck4F2LVHKD+b6FnTRX 0ViHt56ZKXXSf0TFV8s2aAzZc7fRalhb70HWK+4BdavaToqBp0ilq7BP5EMHs6eYd3dF EmpF4m4YQz0pj9iWNAuoNhPvSwRiUgNDcBm430RrPTb8LGbFAQgQNR+wJ7B5fxs+3CaS TQ0KWNtblI8MgyVWVBI49QKV6aJ4kACG0O6xtEW3ybmF6Ygo3RekIJxXVma0q9gpgCdY sopvsh+xJmsrvTPYwWnTxP9ugtcmIPtJ0QvNnFToZobk/u/SWp5Dp0wsUF2eaSSxVe1p 9Ckw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b="FATeKh/L"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1: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 lindbergh.monkeyblade.net (lindbergh.monkeyblade.net. [2620:137:e000::1:18]) by mx.google.com with ESMTPS id bm15-20020a656e8f000000b003c653e92e26si1174563pgb.89.2022.05.17.21.16.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 May 2022 21:16:07 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) client-ip=2620:137:e000::1:18; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b="FATeKh/L"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1: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: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 13CAD7CB17; Tue, 17 May 2022 20:44:53 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232495AbiERARA (ORCPT + 99 others); Tue, 17 May 2022 20:17:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58244 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231556AbiERAQ4 (ORCPT ); Tue, 17 May 2022 20:16:56 -0400 Received: from mail-pf1-x44a.google.com (mail-pf1-x44a.google.com [IPv6:2607:f8b0:4864:20::44a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 82B0C377F7 for ; Tue, 17 May 2022 17:16:55 -0700 (PDT) Received: by mail-pf1-x44a.google.com with SMTP id c4-20020aa79524000000b005180f331899so303028pfp.11 for ; Tue, 17 May 2022 17:16:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=reply-to:date:in-reply-to:message-id:mime-version:references :subject:from:to:cc; bh=rR9QT3FVOBG/jORwlMjkzEP1wf5ezoAh1SN5/FtrVoY=; b=FATeKh/LCpHK6gOSy0gpmtAfUOdYke2XGc3dJ8Hk3Pl1FyF3nl/egXhanbhZJlGBkI vSwXwaPVT0gwXBISR5DobJvih1f5ukLKTgfKZYMqu45YiyIOxI7FqCC17NMfyqzEVW3N e6/uqlg5cTi8eFkGt+je5HkOe8dxeIMRlRfBIPxaV3qRSlRjViHiWImOpos0vew0dfuc Ss4qVLJewDKxSA+WxJnbl/EOoO6wefHTPl/21drTNgPRAkn42q5XkWmGpPJaqRAA+K1R z52SBfDEP950vJw1M46aRekSt0ajx4TBzBTTl+k8nMtUX9MW+e85jwBvcpNuU09stk4v vHuQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:reply-to:date:in-reply-to:message-id :mime-version:references:subject:from:to:cc; bh=rR9QT3FVOBG/jORwlMjkzEP1wf5ezoAh1SN5/FtrVoY=; b=3L+DY7TBo4jVdInZpWaLr+XjJKU7r6X6jk2ej4/5bCrKlRUD0WCk9mkiJi6TJt27Cp AOckO9wQkjKtAxMsx1T5EgnlaY4HFSxk/ip+ZbQTE+grH08yTrUydgxKz+0qO3GVSwT1 FdVdfCM//1AUDCGlUMYLhIw4KqAp8BXSLLg7jHV1kJPitsHAPvDd1e63ILxw/doFGhqm UH2gG+XYusLUp1mKvY14SYp25ytidfiwLbcX0yv6PuIhBs68e26rU0dnWwh3BRqxVwfn lNkkipVF2q+Wg/sJVPYnHOFcAn8RojRcxoW7ky6V62bG3EtFN8cPWqnzQoeRb/emPSbH OPMw== X-Gm-Message-State: AOAM531DZ/wTrshElZOPgem0oIN+bhQlGHPscukN7Nlfmh+LTOVkrzYu 34IFN70+4TlBWuU3H4jAKAxFr/Ou2sg= X-Received: from seanjc.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3e5]) (user=seanjc job=sendgmr) by 2002:a17:90b:1e41:b0:1de:b2dc:b2e with SMTP id pi1-20020a17090b1e4100b001deb2dc0b2emr27643168pjb.69.1652833015045; Tue, 17 May 2022 17:16:55 -0700 (PDT) Reply-To: Sean Christopherson Date: Wed, 18 May 2022 00:16:45 +0000 In-Reply-To: <20220518001647.1291448-1-seanjc@google.com> Message-Id: <20220518001647.1291448-2-seanjc@google.com> Mime-Version: 1.0 References: <20220518001647.1291448-1-seanjc@google.com> X-Mailer: git-send-email 2.36.0.550.gb090851708-goog Subject: [PATCH v2 1/3] x86/crash: Disable virt in core NMI crash handler to avoid double shootdown From: Sean Christopherson To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org Cc: "H. Peter Anvin" , linux-kernel@vger.kernel.org, "Guilherme G . Piccoli" , Vitaly Kuznetsov , Paolo Bonzini , Sean Christopherson Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-9.5 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,RDNS_NONE,SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE, USER_IN_DEF_DKIM_WL autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Disable virtualization in crash_nmi_callback() and rework the emergency_vmx_disable_all() path to do an NMI shootdown if and only if a shootdown has not already occurred. NMI crash shootdown fundamentally can't support multiple invocations as responding CPUs are deliberately put into halt state without unblocking NMIs. But, the emergency reboot path doesn't have any work of its own, it simply cares about disabling virtualization, i.e. so long as a shootdown occurred, emergency reboot doesn't care who initiated the shootdown, or when. If "crash_kexec_post_notifiers" is specified on the kernel command line, panic() will invoke crash_smp_send_stop() and result in a second call to nmi_shootdown_cpus() during native_machine_emergency_restart(). Invoke the callback _before_ disabling virtualization, as the current VMCS needs to be cleared before doing VMXOFF. Note, this results in a subtle change in ordering between disabling virtualization and stopping Intel PT on the responding CPUs. While VMX and Intel PT do interact, VMXOFF and writes to MSR_IA32_RTIT_CTL do not induce faults between one another, which is all that matters when panicking. Harden nmi_shootdown_cpus() against multiple invocations to try and capture any such kernel bugs via a WARN instead of hanging the system during a crash/dump, e.g. prior to the recent hardening of register_nmi_handler(), re-registering the NMI handler would trigger a double list_add() and hang the system if CONFIG_BUG_ON_DATA_CORRUPTION=y. list_add double add: new=ffffffff82220800, prev=ffffffff8221cfe8, next=ffffffff82220800. WARNING: CPU: 2 PID: 1319 at lib/list_debug.c:29 __list_add_valid+0x67/0x70 Call Trace: __register_nmi_handler+0xcf/0x130 nmi_shootdown_cpus+0x39/0x90 native_machine_emergency_restart+0x1c9/0x1d0 panic+0x237/0x29b Extract the disabling logic to a common helper to deduplicate code, and to prepare for doing the shootdown in the emergency reboot path if SVM is supported. Note, prior to commit ed72736183c4 ("x86/reboot: Force all cpus to exit VMX root if VMX is supported"), nmi_shootdown_cpus() was subtly protected against a second invocation by a cpu_vmx_enabled() check as the kdump handler would disable VMX if it ran first. Fixes: ed72736183c4 ("x86/reboot: Force all cpus to exit VMX root if VMX is supported) Cc: stable@vger.kernel.org Reported-by: Guilherme G. Piccoli Cc: Vitaly Kuznetsov Cc: Paolo Bonzini Link: https://lore.kernel.org/all/20220427224924.592546-2-gpiccoli@igalia.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/reboot.h | 1 + arch/x86/kernel/crash.c | 16 +-------- arch/x86/kernel/reboot.c | 66 ++++++++++++++++++++++++++++------- 3 files changed, 56 insertions(+), 27 deletions(-) diff --git a/arch/x86/include/asm/reboot.h b/arch/x86/include/asm/reboot.h index 04c17be9b5fd..8f2da36435a6 100644 --- a/arch/x86/include/asm/reboot.h +++ b/arch/x86/include/asm/reboot.h @@ -25,6 +25,7 @@ void __noreturn machine_real_restart(unsigned int type); #define MRR_BIOS 0 #define MRR_APM 1 +void cpu_crash_disable_virtualization(void); typedef void (*nmi_shootdown_cb)(int, struct pt_regs*); void nmi_panic_self_stop(struct pt_regs *regs); void nmi_shootdown_cpus(nmi_shootdown_cb callback); diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index e8326a8d1c5d..fe0cf83843ba 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c @@ -81,15 +81,6 @@ static void kdump_nmi_callback(int cpu, struct pt_regs *regs) */ cpu_crash_vmclear_loaded_vmcss(); - /* Disable VMX or SVM if needed. - * - * We need to disable virtualization on all CPUs. - * Having VMX or SVM enabled on any CPU may break rebooting - * after the kdump kernel has finished its task. - */ - cpu_emergency_vmxoff(); - cpu_emergency_svm_disable(); - /* * Disable Intel PT to stop its logging */ @@ -148,12 +139,7 @@ void native_machine_crash_shutdown(struct pt_regs *regs) */ cpu_crash_vmclear_loaded_vmcss(); - /* Booting kdump kernel with VMX or SVM enabled won't work, - * because (among other limitations) we can't disable paging - * with the virt flags. - */ - cpu_emergency_vmxoff(); - cpu_emergency_svm_disable(); + cpu_crash_disable_virtualization(); /* * Disable Intel PT to stop its logging diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index fa700b46588e..e67737418f7d 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -528,10 +528,7 @@ static inline void kb_wait(void) } } -static void vmxoff_nmi(int cpu, struct pt_regs *regs) -{ - cpu_emergency_vmxoff(); -} +static inline void nmi_shootdown_cpus_on_restart(void); /* Use NMIs as IPIs to tell all CPUs to disable virtualization */ static void emergency_vmx_disable_all(void) @@ -554,7 +551,7 @@ static void emergency_vmx_disable_all(void) __cpu_emergency_vmxoff(); /* Halt and exit VMX root operation on the other CPUs. */ - nmi_shootdown_cpus(vmxoff_nmi); + nmi_shootdown_cpus_on_restart(); } } @@ -802,6 +799,18 @@ static nmi_shootdown_cb shootdown_callback; static atomic_t waiting_for_crash_ipi; static int crash_ipi_issued; +void cpu_crash_disable_virtualization(void) +{ + /* + * Disable virtualization, i.e. VMX or SVM, so that INIT is recognized + * during reboot. VMX blocks INIT if the CPU is post-VMXON, and SVM + * blocks INIT if GIF=0. Note, CLGI #UDs if SVM isn't enabled, so it's + * easier to just disable SVM unconditionally. + */ + cpu_emergency_vmxoff(); + cpu_emergency_svm_disable(); +} + static int crash_nmi_callback(unsigned int val, struct pt_regs *regs) { int cpu; @@ -817,7 +826,14 @@ static int crash_nmi_callback(unsigned int val, struct pt_regs *regs) return NMI_HANDLED; local_irq_disable(); - shootdown_callback(cpu, regs); + if (shootdown_callback) + shootdown_callback(cpu, regs); + + /* + * Prepare the CPU for reboot _after_ invoking the callback so that the + * callback can safely use virtualization instructions, e.g. VMCLEAR. + */ + cpu_crash_disable_virtualization(); atomic_dec(&waiting_for_crash_ipi); /* Assume hlt works */ @@ -828,18 +844,32 @@ static int crash_nmi_callback(unsigned int val, struct pt_regs *regs) return NMI_HANDLED; } -/* - * Halt all other CPUs, calling the specified function on each of them +/** + * nmi_shootdown_cpus - Stop other CPUs via NMI + * @callback: Optional callback to be invoked from the NMI handler * - * This function can be used to halt all other CPUs on crash - * or emergency reboot time. The function passed as parameter - * will be called inside a NMI handler on all CPUs. + * The NMI handler on the remote CPUs invokes @callback, if not + * NULL, first and then disables virtualization to ensure that + * INIT is recognized during reboot. + * + * nmi_shootdown_cpus() can only be invoked once. After the first + * invocation all other CPUs are stuck in crash_nmi_callback() and + * cannot respond to a second NMI. */ void nmi_shootdown_cpus(nmi_shootdown_cb callback) { unsigned long msecs; + local_irq_disable(); + /* + * Avoid certain doom if a shootdown already occurred; re-registering + * the NMI handler will cause list corruption, modifying the callback + * will do who knows what, etc... + */ + if (WARN_ON_ONCE(crash_ipi_issued)) + return; + /* Make a note of crashing cpu. Will be used in NMI callback. */ crashing_cpu = safe_smp_processor_id(); @@ -867,7 +897,17 @@ void nmi_shootdown_cpus(nmi_shootdown_cb callback) msecs--; } - /* Leave the nmi callback set */ + /* + * Leave the nmi callback set, shootdown is a one-time thing. Clearing + * the callback could result in a NULL pointer dereference if a CPU + * (finally) responds after the timeout expires. + */ +} + +static inline void nmi_shootdown_cpus_on_restart(void) +{ + if (!crash_ipi_issued) + nmi_shootdown_cpus(NULL); } /* @@ -897,6 +937,8 @@ void nmi_shootdown_cpus(nmi_shootdown_cb callback) /* No other CPUs to shoot down */ } +static inline void nmi_shootdown_cpus_on_restart(void) { } + void run_crash_ipi_callback(struct pt_regs *regs) { } -- 2.36.0.550.gb090851708-goog