From nobody Thu May 7 19:54:38 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8C1EBC433EF for ; Fri, 20 May 2022 03:14:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345101AbiETDOJ (ORCPT ); Thu, 19 May 2022 23:14:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45988 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345076AbiETDNi (ORCPT ); Thu, 19 May 2022 23:13:38 -0400 Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2B5D0149DB0 for ; Thu, 19 May 2022 20:13:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1653016418; x=1684552418; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=C1MjNgZRWNUguHYARwDuQ5aWYg8MLB/+yAZkGdkF1+w=; b=WdINQdLof7yg+tkakQI025hdkYxkuzFc/Go22QdqCRZltZrnZmAKjUCw Sz9BNCXf76wB9b7SLQ5gtno5A56i9Y5VAVMlWfdeKEq6cGdn6zD62mDUE eEuDZv45O3MoqYtkRPuR8Lc2vfCIUKUF9VS0yjt9mexwfwZU1M/1J0TFj j2N1gJkXPGgfpKIOutsTMuXZ8NGf/IqYE/OcEcQ/PxMRY8lr4En4d+yjW p1IiyKfdxQI+bKC+UnBmerIVw2Eb2h7K+udYBiR3+mnGYQABtgM7IEHco UghxlMvyL/xjTPtzlqkrbOHMXSO7B2Fzddt+Rw41whwvxkersbyHqQG1t w==; X-IronPort-AV: E=McAfee;i="6400,9594,10352"; a="272594681" X-IronPort-AV: E=Sophos;i="5.91,238,1647327600"; d="scan'208";a="272594681" Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 May 2022 20:13:28 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.91,238,1647327600"; d="scan'208";a="627932247" Received: from black.fi.intel.com ([10.237.72.28]) by fmsmga008.fm.intel.com with ESMTP; 19 May 2022 20:13:24 -0700 Received: by black.fi.intel.com (Postfix, from userid 1000) id E9212D2; Fri, 20 May 2022 06:13:24 +0300 (EEST) From: "Kirill A. Shutemov" To: tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, dave.hansen@intel.com, luto@kernel.org, peterz@infradead.org Cc: ak@linux.intel.com, dan.j.williams@intel.com, david@redhat.com, hpa@zytor.com, linux-kernel@vger.kernel.org, sathyanarayanan.kuppuswamy@linux.intel.com, seanjc@google.com, thomas.lendacky@amd.com, x86@kernel.org, "Kirill A. Shutemov" Subject: [PATCHv2 1/3] x86/tdx: Fix early #VE handling Date: Fri, 20 May 2022 06:13:14 +0300 Message-Id: <20220520031316.47722-2-kirill.shutemov@linux.intel.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220520031316.47722-1-kirill.shutemov@linux.intel.com> References: <20220520031316.47722-1-kirill.shutemov@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Move RIP in tdx_early_handle_ve() after handling the exception. Failure to do that leads to infinite loop of exceptions. Signed-off-by: Kirill A. Shutemov Fixes: 32e72854fa5f ("x86/tdx: Port I/O: Add early boot support") Reviewed-by: Kuppuswamy Sathyanarayanan=20 --- arch/x86/coco/tdx/tdx.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index 03deb4d6920d..faae53f8d559 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -447,13 +447,17 @@ static bool handle_io(struct pt_regs *regs, u32 exit_= qual) __init bool tdx_early_handle_ve(struct pt_regs *regs) { struct ve_info ve; + bool ret; =20 tdx_get_ve_info(&ve); =20 if (ve.exit_reason !=3D EXIT_REASON_IO_INSTRUCTION) return false; =20 - return handle_io(regs, ve.exit_qual); + ret =3D handle_io(regs, ve.exit_qual); + if (ret) + regs->ip +=3D ve.instr_len; + return ret; } =20 void tdx_get_ve_info(struct ve_info *ve) --=20 2.35.1 From nobody Thu May 7 19:54:38 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A70B7C433F5 for ; Fri, 20 May 2022 03:13:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345068AbiETDNe (ORCPT ); Thu, 19 May 2022 23:13:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45910 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244166AbiETDNa (ORCPT ); Thu, 19 May 2022 23:13:30 -0400 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 094FA149DA0 for ; Thu, 19 May 2022 20:13:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1653016409; x=1684552409; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Iq4pXgGzuLF/11wA2Vl6zMmV+1DHUunV01OtWnlWK9A=; b=M7ZXsIICiaSjYGlBFLyYGNXZtbCzLJDhHuk8o5SMTyxrN0g/7oN2ENzc C71r9DzTwbcrhfKgiq38HAj9WYZEV6WzViiuxzV+UxFYt/e0QzY98y/Y1 IIYxnXuIlrqhn1uzSUgMV2AbRLMnxqnbWMlIgjfjP6xim0V9aBgIjSJFS GyDQ/H5aI+WprcPPVtLuwgwELC74YmNYO2eLXK10xlZpcyc1SV7DQmjRQ YXMTda9B2r1Z3xGjadzsQZRSPpXYOgQ5vc5tLwFdbqQmgsZzTV1b/OW7o Dn65xUyjhuR0Giokvgs4CoTNshdWiW01T+osth4RNHTepvOt9BWggmvkN Q==; X-IronPort-AV: E=McAfee;i="6400,9594,10352"; a="254517995" X-IronPort-AV: E=Sophos;i="5.91,238,1647327600"; d="scan'208";a="254517995" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 May 2022 20:13:28 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.91,238,1647327600"; d="scan'208";a="743279989" Received: from black.fi.intel.com ([10.237.72.28]) by orsmga005.jf.intel.com with ESMTP; 19 May 2022 20:13:24 -0700 Received: by black.fi.intel.com (Postfix, from userid 1000) id 00055501; Fri, 20 May 2022 06:13:24 +0300 (EEST) From: "Kirill A. Shutemov" To: tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, dave.hansen@intel.com, luto@kernel.org, peterz@infradead.org Cc: ak@linux.intel.com, dan.j.williams@intel.com, david@redhat.com, hpa@zytor.com, linux-kernel@vger.kernel.org, sathyanarayanan.kuppuswamy@linux.intel.com, seanjc@google.com, thomas.lendacky@amd.com, x86@kernel.org, "Kirill A. Shutemov" Subject: [PATCHv2 2/3] x86/tdx: Clarify RIP adjustments in #VE handler Date: Fri, 20 May 2022 06:13:15 +0300 Message-Id: <20220520031316.47722-3-kirill.shutemov@linux.intel.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220520031316.47722-1-kirill.shutemov@linux.intel.com> References: <20220520031316.47722-1-kirill.shutemov@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" After successful #VE handling, tdx_handle_virt_exception() has to move RIP to the next instruction. The handler needs to know the length of the instruction. If the #VE happened due to instruction execution, GET_VEINFO TDX module call provides info on the instruction in R10, including its length. For #VE due to EPT violation, info in R10 is not usable and kernel has to decode instruction manually to find out its length. Restructure the code to make it explicit that the instruction length depends on the type of #VE. Handler of an exit reason returns instruction length on success or -errno on failure. Suggested-by: Dave Hansen Signed-off-by: Kirill A. Shutemov --- arch/x86/coco/tdx/tdx.c | 150 +++++++++++++++++++++++++--------------- 1 file changed, 93 insertions(+), 57 deletions(-) diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index faae53f8d559..010dc229096a 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -147,7 +147,7 @@ static u64 __cpuidle __halt(const bool irq_disabled, co= nst bool do_sti) return __tdx_hypercall(&args, do_sti ? TDX_HCALL_ISSUE_STI : 0); } =20 -static bool handle_halt(void) +static int handle_halt(struct ve_info *ve) { /* * Since non safe halt is mainly used in CPU offlining @@ -158,9 +158,9 @@ static bool handle_halt(void) const bool do_sti =3D false; =20 if (__halt(irq_disabled, do_sti)) - return false; + return -EIO; =20 - return true; + return ve->instr_len; } =20 void __cpuidle tdx_safe_halt(void) @@ -180,7 +180,7 @@ void __cpuidle tdx_safe_halt(void) WARN_ONCE(1, "HLT instruction emulation failed\n"); } =20 -static bool read_msr(struct pt_regs *regs) +static int read_msr(struct pt_regs *regs, struct ve_info *ve) { struct tdx_hypercall_args args =3D { .r10 =3D TDX_HYPERCALL_STANDARD, @@ -194,14 +194,14 @@ static bool read_msr(struct pt_regs *regs) * (GHCI), section titled "TDG.VP.VMCALL". */ if (__tdx_hypercall(&args, TDX_HCALL_HAS_OUTPUT)) - return false; + return -EIO; =20 regs->ax =3D lower_32_bits(args.r11); regs->dx =3D upper_32_bits(args.r11); - return true; + return ve->instr_len; } =20 -static bool write_msr(struct pt_regs *regs) +static int write_msr(struct pt_regs *regs, struct ve_info *ve) { struct tdx_hypercall_args args =3D { .r10 =3D TDX_HYPERCALL_STANDARD, @@ -215,10 +215,13 @@ static bool write_msr(struct pt_regs *regs) * can be found in TDX Guest-Host-Communication Interface * (GHCI) section titled "TDG.VP.VMCALL". */ - return !__tdx_hypercall(&args, 0); + if (__tdx_hypercall(&args, 0)) + return -EIO; + + return ve->instr_len; } =20 -static bool handle_cpuid(struct pt_regs *regs) +static int handle_cpuid(struct pt_regs *regs, struct ve_info *ve) { struct tdx_hypercall_args args =3D { .r10 =3D TDX_HYPERCALL_STANDARD, @@ -236,7 +239,7 @@ static bool handle_cpuid(struct pt_regs *regs) */ if (regs->ax < 0x40000000 || regs->ax > 0x4FFFFFFF) { regs->ax =3D regs->bx =3D regs->cx =3D regs->dx =3D 0; - return true; + return ve->instr_len; } =20 /* @@ -245,7 +248,7 @@ static bool handle_cpuid(struct pt_regs *regs) * (GHCI), section titled "VP.VMCALL". */ if (__tdx_hypercall(&args, TDX_HCALL_HAS_OUTPUT)) - return false; + return -EIO; =20 /* * As per TDX GHCI CPUID ABI, r12-r15 registers contain contents of @@ -257,7 +260,7 @@ static bool handle_cpuid(struct pt_regs *regs) regs->cx =3D args.r14; regs->dx =3D args.r15; =20 - return true; + return ve->instr_len; } =20 static bool mmio_read(int size, unsigned long addr, unsigned long *val) @@ -283,7 +286,7 @@ static bool mmio_write(int size, unsigned long addr, un= signed long val) EPT_WRITE, addr, val); } =20 -static bool handle_mmio(struct pt_regs *regs, struct ve_info *ve) +static int handle_mmio(struct pt_regs *regs, struct ve_info *ve) { char buffer[MAX_INSN_SIZE]; unsigned long *reg, val; @@ -294,34 +297,36 @@ static bool handle_mmio(struct pt_regs *regs, struct = ve_info *ve) =20 /* Only in-kernel MMIO is supported */ if (WARN_ON_ONCE(user_mode(regs))) - return false; + return -EFAULT; =20 if (copy_from_kernel_nofault(buffer, (void *)regs->ip, MAX_INSN_SIZE)) - return false; + return -EFAULT; =20 if (insn_decode(&insn, buffer, MAX_INSN_SIZE, INSN_MODE_64)) - return false; + return -EINVAL; =20 mmio =3D insn_decode_mmio(&insn, &size); if (WARN_ON_ONCE(mmio =3D=3D MMIO_DECODE_FAILED)) - return false; + return -EINVAL; =20 if (mmio !=3D MMIO_WRITE_IMM && mmio !=3D MMIO_MOVS) { reg =3D insn_get_modrm_reg_ptr(&insn, regs); if (!reg) - return false; + return -EINVAL; } =20 - ve->instr_len =3D insn.length; - /* Handle writes first */ switch (mmio) { case MMIO_WRITE: memcpy(&val, reg, size); - return mmio_write(size, ve->gpa, val); + if (!mmio_write(size, ve->gpa, val)) + return -EIO; + return insn.length; case MMIO_WRITE_IMM: val =3D insn.immediate.value; - return mmio_write(size, ve->gpa, val); + if (!mmio_write(size, ve->gpa, val)) + return -EIO; + return insn.length; case MMIO_READ: case MMIO_READ_ZERO_EXTEND: case MMIO_READ_SIGN_EXTEND: @@ -334,15 +339,15 @@ static bool handle_mmio(struct pt_regs *regs, struct = ve_info *ve) * decoded or handled properly. It was likely not using io.h * helpers or accessed MMIO accidentally. */ - return false; + return -EINVAL; default: WARN_ONCE(1, "Unknown insn_decode_mmio() decode value?"); - return false; + return -EINVAL; } =20 /* Handle reads */ if (!mmio_read(size, ve->gpa, &val)) - return false; + return -EIO; =20 switch (mmio) { case MMIO_READ: @@ -364,13 +369,13 @@ static bool handle_mmio(struct pt_regs *regs, struct = ve_info *ve) default: /* All other cases has to be covered with the first switch() */ WARN_ON_ONCE(1); - return false; + return -EINVAL; } =20 if (extend_size) memset(reg, extend_val, extend_size); memcpy(reg, &val, size); - return true; + return insn.length; } =20 static bool handle_in(struct pt_regs *regs, int size, int port) @@ -421,13 +426,14 @@ static bool handle_out(struct pt_regs *regs, int size= , int port) * * Return True on success or False on failure. */ -static bool handle_io(struct pt_regs *regs, u32 exit_qual) +static int handle_io(struct pt_regs *regs, struct ve_info *ve) { + u32 exit_qual =3D ve->exit_qual; int size, port; - bool in; + bool in, ret; =20 if (VE_IS_IO_STRING(exit_qual)) - return false; + return -EIO; =20 in =3D VE_IS_IO_IN(exit_qual); size =3D VE_GET_IO_SIZE(exit_qual); @@ -435,9 +441,13 @@ static bool handle_io(struct pt_regs *regs, u32 exit_q= ual) =20 =20 if (in) - return handle_in(regs, size, port); + ret =3D handle_in(regs, size, port); else - return handle_out(regs, size, port); + ret =3D handle_out(regs, size, port); + if (!ret) + return -EIO; + + return ve->instr_len; } =20 /* @@ -447,17 +457,19 @@ static bool handle_io(struct pt_regs *regs, u32 exit_= qual) __init bool tdx_early_handle_ve(struct pt_regs *regs) { struct ve_info ve; - bool ret; + int insn_len; =20 tdx_get_ve_info(&ve); =20 if (ve.exit_reason !=3D EXIT_REASON_IO_INSTRUCTION) return false; =20 - ret =3D handle_io(regs, ve.exit_qual); - if (ret) - regs->ip +=3D ve.instr_len; - return ret; + insn_len =3D handle_io(regs, &ve); + if (insn_len < 0) + return false; + + regs->ip +=3D insn_len; + return true; } =20 void tdx_get_ve_info(struct ve_info *ve) @@ -486,58 +498,82 @@ void tdx_get_ve_info(struct ve_info *ve) ve->exit_qual =3D out.rdx; ve->gla =3D out.r8; ve->gpa =3D out.r9; - ve->instr_len =3D lower_32_bits(out.r10); - ve->instr_info =3D upper_32_bits(out.r10); + + /* + * If the #VE happened due to instruction execution, GET_VEINFO + * provides info on the instruction in out.r10. + * + * For #VE due to EPT violation, info in out.r10 is not usable and + * kernel has to decode instruction manually to find out its length. + */ + if (ve->exit_reason !=3D EXIT_REASON_EPT_VIOLATION) { + ve->instr_len =3D lower_32_bits(out.r10); + ve->instr_info =3D upper_32_bits(out.r10); + } else { + ve->instr_len =3D 0; + ve->instr_info =3D 0; + } } =20 -/* Handle the user initiated #VE */ -static bool virt_exception_user(struct pt_regs *regs, struct ve_info *ve) +/* + * Handle the user initiated #VE. + * + * On success, returns the number of bytes RIP should be incremented (>=3D= 0) + * or -errno on error. + */ +static int virt_exception_user(struct pt_regs *regs, struct ve_info *ve) { switch (ve->exit_reason) { case EXIT_REASON_CPUID: - return handle_cpuid(regs); + return handle_cpuid(regs, ve); default: pr_warn("Unexpected #VE: %lld\n", ve->exit_reason); - return false; + return -EIO; } } =20 -/* Handle the kernel #VE */ -static bool virt_exception_kernel(struct pt_regs *regs, struct ve_info *ve) +/* + * Handle the kernel #VE. + * + * On success, returns the number of bytes RIP should be incremented (>=3D= 0) + * or -errno on error. + */ +static int virt_exception_kernel(struct pt_regs *regs, struct ve_info *ve) { switch (ve->exit_reason) { case EXIT_REASON_HLT: - return handle_halt(); + return handle_halt(ve); case EXIT_REASON_MSR_READ: - return read_msr(regs); + return read_msr(regs, ve); case EXIT_REASON_MSR_WRITE: - return write_msr(regs); + return write_msr(regs, ve); case EXIT_REASON_CPUID: - return handle_cpuid(regs); + return handle_cpuid(regs, ve); case EXIT_REASON_EPT_VIOLATION: return handle_mmio(regs, ve); case EXIT_REASON_IO_INSTRUCTION: - return handle_io(regs, ve->exit_qual); + return handle_io(regs, ve); default: pr_warn("Unexpected #VE: %lld\n", ve->exit_reason); - return false; + return -EIO; } } =20 bool tdx_handle_virt_exception(struct pt_regs *regs, struct ve_info *ve) { - bool ret; + int insn_len; =20 if (user_mode(regs)) - ret =3D virt_exception_user(regs, ve); + insn_len =3D virt_exception_user(regs, ve); else - ret =3D virt_exception_kernel(regs, ve); + insn_len =3D virt_exception_kernel(regs, ve); + if (insn_len < 0) + return false; =20 /* After successful #VE handling, move the IP */ - if (ret) - regs->ip +=3D ve->instr_len; + regs->ip +=3D insn_len; =20 - return ret; + return true; } =20 static bool tdx_tlb_flush_required(bool private) --=20 2.35.1 From nobody Thu May 7 19:54:38 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 350DDC433F5 for ; Fri, 20 May 2022 03:13:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343821AbiETDNw (ORCPT ); Thu, 19 May 2022 23:13:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45994 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345073AbiETDNj (ORCPT ); Thu, 19 May 2022 23:13:39 -0400 Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2489A149D9D for ; Thu, 19 May 2022 20:13:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1653016418; x=1684552418; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=zI9dty8xwA0hQXIR/uJZISyrrrAzLIt9y6FokLyHGTc=; b=CIrkJvGW9pDBXCkwe0o2UUVPTHk72j62anI2x99d+Ljbbpq3pxfoZAQp Av22iGSFun5UC+5j86G5yKKC9l4i64zDmlXpxeSxF42o/3DUiWLNujLy8 x0XoIK9q9V1phhHESZMaOyAetB55yUQ8O9yGAqnjBoHpfwYILppzwtwH8 5JeeUS1Qw/6PNODVHgbKFArTWR4eX/NEj33xyyz3m3xWUB0WekZNKgbQg p3up7N1BY7+T9PoAkhXwLqg+cnKCQII42YJ5qxEJPe50PxPLv21AVMKq0 oLjkUEnnsoII+qhWTDxQi+qri02weQMZk2pX8E0tNrfY5cejlMiLdhl3Y A==; X-IronPort-AV: E=McAfee;i="6400,9594,10352"; a="335517346" X-IronPort-AV: E=Sophos;i="5.91,238,1647327600"; d="scan'208";a="335517346" Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 May 2022 20:13:28 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.91,238,1647327600"; d="scan'208";a="674404235" Received: from black.fi.intel.com ([10.237.72.28]) by fmsmga002.fm.intel.com with ESMTP; 19 May 2022 20:13:24 -0700 Received: by black.fi.intel.com (Postfix, from userid 1000) id 05CAA27D; Fri, 20 May 2022 06:13:25 +0300 (EEST) From: "Kirill A. Shutemov" To: tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, dave.hansen@intel.com, luto@kernel.org, peterz@infradead.org Cc: ak@linux.intel.com, dan.j.williams@intel.com, david@redhat.com, hpa@zytor.com, linux-kernel@vger.kernel.org, sathyanarayanan.kuppuswamy@linux.intel.com, seanjc@google.com, thomas.lendacky@amd.com, x86@kernel.org, "Kirill A. Shutemov" Subject: [PATCHv2 3/3] x86/tdx: Handle load_unaligned_zeropad() page-cross to a shared page Date: Fri, 20 May 2022 06:13:16 +0300 Message-Id: <20220520031316.47722-4-kirill.shutemov@linux.intel.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220520031316.47722-1-kirill.shutemov@linux.intel.com> References: <20220520031316.47722-1-kirill.shutemov@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" load_unaligned_zeropad() can lead to unwanted loads across page boundaries. The unwanted loads are typically harmless. But, they might be made to totally unrelated or even unmapped memory. load_unaligned_zeropad() relies on exception fixup (#PF, #GP and now #VE) to recover from these unwanted loads. In TDX guests, the second page can be shared page and VMM may configure it to trigger #VE. Kernel assumes that #VE on a shared page is MMIO access and tries to decode instruction to handle it. In case of load_unaligned_zeropad() it may result in confusion as it is not MMIO access. Check fixup table before trying to handle MMIO. The issue was discovered by analysis. It was not triggered during the testing. Signed-off-by: Kirill A. Shutemov --- arch/x86/coco/tdx/tdx.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index 010dc229096a..1a1c8a92cfa5 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include =20 /* TDX module Call Leaf IDs */ #define TDX_GET_INFO 1 @@ -299,6 +301,24 @@ static int handle_mmio(struct pt_regs *regs, struct ve= _info *ve) if (WARN_ON_ONCE(user_mode(regs))) return -EFAULT; =20 + /* + * load_unaligned_zeropad() relies on exception fixups in case of the + * word being a page-crosser and the second page is not accessible. + * + * In TDX guests, the second page can be shared page and VMM may + * configure it to trigger #VE. + * + * Kernel assumes that #VE on a shared page is MMIO access and tries to + * decode instruction to handle it. In case of load_unaligned_zeropad() + * it may result in confusion as it is not MMIO access. + * + * Check fixup table before trying to handle MMIO. + */ + if (fixup_exception(regs, X86_TRAP_VE, 0, ve->gla)) { + /* regs->ip is adjusted by fixup_exception() */ + return 0; + } + if (copy_from_kernel_nofault(buffer, (void *)regs->ip, MAX_INSN_SIZE)) return -EFAULT; =20 --=20 2.35.1