From nobody Tue Feb 10 03:01:59 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0F5481BC09D; Fri, 16 Aug 2024 13:44:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815896; cv=none; b=W0bydNYVGrO5Cw5sevhPWLqFQ1TOi7yuevwFbS39jEUhm3pnvXM07CQF0z0cXGo5oMpPi5uSbQHeT3HEH5OiA96wVg2kNYtn8ldzEZmV84M6Ts7Fua6J2CnL/51RfLGfUXVXHvCRRXmHRJplgx/W31nlx8q/aEynWClt7fTqEZo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815896; c=relaxed/simple; bh=enUsG3Ei73Psklt1F2kFNG5sBo40CkaEm1EeVKdKNZA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XvrppbQotdpvr6ZGTEFdcW8CXdtceC6xxUOa2JqECB7YfMogCbpokgG64oqASu0WR4v8CoFLUgBtjm9Ni5oQNVe6Zz5rfhAJNu+ckq+7EhsBSCIoIOJpiS5YlRi37IhPCok+PuIke9bVlAXmnPz+MKDSDqkZ0EsykvkYIoJExHc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=bLxcfXsV; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="bLxcfXsV" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B6056C4AF09; Fri, 16 Aug 2024 13:44:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1723815895; bh=enUsG3Ei73Psklt1F2kFNG5sBo40CkaEm1EeVKdKNZA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bLxcfXsVno2kRukkACyH9WzAC7AUVpvXXz12AhHQRP7d9/2qZLDrWWY47eH3QixZ5 3N+C7JJTYIsIksT3SBZre/KdL42mJ7mzRvQ9KTMy1n9qxwq4XIOOCfn8fzPRfA9GRc Be2uvKWKuVdvZ8qNJ2ETW6nxgPqtOrASjI/MW2pbtvo1AiOnY6Mk5dQ1wDmomt3eYh zRLkVzaWLs1wb9uo84zBOlQj6ZmE4A6bsjK6lHI7niCZZWkHhyUcMj+JsrJ22ZS8ik iy7PBaGtbfNNLfhtLgPaV+vpE34vPCcV46bLwt8I3436yoUQHleQHYWXsspjHVDpcw /uyDV2scECvEg== From: Alexey Gladkov To: linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev Cc: "Alexey Gladkov (Intel)" , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , "H. Peter Anvin" , "Kirill A. Shutemov" , Andrew Morton , Yuan Yao , Geert Uytterhoeven , Yuntao Wang , Kai Huang , Baoquan He , Oleg Nesterov , cho@microsoft.com, decui@microsoft.com, John.Starks@microsoft.com Subject: [PATCH v3 01/10] x86/tdx: Split MMIO read and write operations Date: Fri, 16 Aug 2024 15:43:51 +0200 Message-ID: <0b5f95e9c7639ddb6e4cbd99b3904e6538e91371.1723807851.git.legion@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Alexey Gladkov (Intel)" To implement MMIO in userspace, additional memory checks need to be implemented. To avoid overly complicating the handle_mmio() function and to separate checks from actions, it would be better to split this function into two separate functions to handle read and write operations. Signed-off-by: Alexey Gladkov (Intel) Reviewed-by: Kirill A. Shutemov --- arch/x86/coco/tdx/tdx.c | 136 ++++++++++++++++++++++++---------------- 1 file changed, 83 insertions(+), 53 deletions(-) diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index 078e2bac2553..af0b6c1cacf7 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -405,14 +405,91 @@ static bool mmio_write(int size, unsigned long addr, = unsigned long val) EPT_WRITE, addr, val); } =20 +static int handle_mmio_write(struct insn *insn, enum insn_mmio_type mmio, = int size, + struct pt_regs *regs, struct ve_info *ve) +{ + unsigned long *reg, val; + + switch (mmio) { + case INSN_MMIO_WRITE: + reg =3D insn_get_modrm_reg_ptr(insn, regs); + if (!reg) + return -EINVAL; + memcpy(&val, reg, size); + if (!mmio_write(size, ve->gpa, val)) + return -EIO; + return insn->length; + case INSN_MMIO_WRITE_IMM: + val =3D insn->immediate.value; + if (!mmio_write(size, ve->gpa, val)) + return -EIO; + return insn->length; + case INSN_MMIO_MOVS: + /* + * MMIO was accessed with an instruction that could not be + * decoded or handled properly. It was likely not using io.h + * helpers or accessed MMIO accidentally. + */ + return -EINVAL; + default: + WARN_ON_ONCE(1); + return -EINVAL; + } + + return insn->length; +} + +static int handle_mmio_read(struct insn *insn, enum insn_mmio_type mmio, i= nt size, + struct pt_regs *regs, struct ve_info *ve) +{ + unsigned long *reg, val; + int extend_size; + u8 extend_val; + + reg =3D insn_get_modrm_reg_ptr(insn, regs); + if (!reg) + return -EINVAL; + + if (!mmio_read(size, ve->gpa, &val)) + return -EIO; + + extend_val =3D 0; + + switch (mmio) { + case INSN_MMIO_READ: + /* Zero-extend for 32-bit operation */ + extend_size =3D size =3D=3D 4 ? sizeof(*reg) : 0; + break; + case INSN_MMIO_READ_ZERO_EXTEND: + /* Zero extend based on operand size */ + extend_size =3D insn->opnd_bytes; + break; + case INSN_MMIO_READ_SIGN_EXTEND: + /* Sign extend based on operand size */ + extend_size =3D insn->opnd_bytes; + if (size =3D=3D 1 && val & BIT(7)) + extend_val =3D 0xFF; + else if (size > 1 && val & BIT(15)) + extend_val =3D 0xFF; + break; + default: + WARN_ON_ONCE(1); + return -EINVAL; + } + + if (extend_size) + memset(reg, extend_val, extend_size); + memcpy(reg, &val, size); + return insn->length; +} + static int handle_mmio(struct pt_regs *regs, struct ve_info *ve) { - unsigned long *reg, val, vaddr; char buffer[MAX_INSN_SIZE]; enum insn_mmio_type mmio; struct insn insn =3D {}; - int size, extend_size; - u8 extend_val =3D 0; + unsigned long vaddr; + int size; =20 /* Only in-kernel MMIO is supported */ if (WARN_ON_ONCE(user_mode(regs))) @@ -428,12 +505,6 @@ static int handle_mmio(struct pt_regs *regs, struct ve= _info *ve) if (WARN_ON_ONCE(mmio =3D=3D INSN_MMIO_DECODE_FAILED)) return -EINVAL; =20 - if (mmio !=3D INSN_MMIO_WRITE_IMM && mmio !=3D INSN_MMIO_MOVS) { - reg =3D insn_get_modrm_reg_ptr(&insn, regs); - if (!reg) - return -EINVAL; - } - /* * Reject EPT violation #VEs that split pages. * @@ -447,24 +518,15 @@ static int handle_mmio(struct pt_regs *regs, struct v= e_info *ve) if (vaddr / PAGE_SIZE !=3D (vaddr + size - 1) / PAGE_SIZE) return -EFAULT; =20 - /* Handle writes first */ switch (mmio) { case INSN_MMIO_WRITE: - memcpy(&val, reg, size); - if (!mmio_write(size, ve->gpa, val)) - return -EIO; - return insn.length; case INSN_MMIO_WRITE_IMM: - val =3D insn.immediate.value; - if (!mmio_write(size, ve->gpa, val)) - return -EIO; - return insn.length; + case INSN_MMIO_MOVS: + return handle_mmio_write(&insn, mmio, size, regs, ve); case INSN_MMIO_READ: case INSN_MMIO_READ_ZERO_EXTEND: case INSN_MMIO_READ_SIGN_EXTEND: - /* Reads are handled below */ - break; - case INSN_MMIO_MOVS: + return handle_mmio_read(&insn, mmio, size, regs, ve); case INSN_MMIO_DECODE_FAILED: /* * MMIO was accessed with an instruction that could not be @@ -476,38 +538,6 @@ static int handle_mmio(struct pt_regs *regs, struct ve= _info *ve) WARN_ONCE(1, "Unknown insn_decode_mmio() decode value?"); return -EINVAL; } - - /* Handle reads */ - if (!mmio_read(size, ve->gpa, &val)) - return -EIO; - - switch (mmio) { - case INSN_MMIO_READ: - /* Zero-extend for 32-bit operation */ - extend_size =3D size =3D=3D 4 ? sizeof(*reg) : 0; - break; - case INSN_MMIO_READ_ZERO_EXTEND: - /* Zero extend based on operand size */ - extend_size =3D insn.opnd_bytes; - break; - case INSN_MMIO_READ_SIGN_EXTEND: - /* Sign extend based on operand size */ - extend_size =3D insn.opnd_bytes; - if (size =3D=3D 1 && val & BIT(7)) - extend_val =3D 0xFF; - else if (size > 1 && val & BIT(15)) - extend_val =3D 0xFF; - break; - default: - /* All other cases has to be covered with the first switch() */ - WARN_ON_ONCE(1); - return -EINVAL; - } - - if (extend_size) - memset(reg, extend_val, extend_size); - memcpy(reg, &val, size); - return insn.length; } =20 static bool handle_in(struct pt_regs *regs, int size, int port) --=20 2.45.2 From nobody Tue Feb 10 03:01:59 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0C1091BC09D; Fri, 16 Aug 2024 13:45:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815900; cv=none; b=RMBMOmVMveWoMP6iL4HB5h8KneK0uS4bZCR8EIvQ7MhrwP3r84FxDnet+TnMitSAqc1vhqMRsar7Rv9w8QAjbe2cQIMNCvamWcmpkAq6U+8833rbVQpj5AUx7e4GjvqwWM3ylIPfNrqTBN/ZDms70rmCd0eSS2nJ3hHxdlPVrk4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815900; c=relaxed/simple; bh=1scx8whBOKjnrrkIQ8ohdv6xkBmx+W6qwhZSeMPIvKs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=uYaL5Fk6wyuqR2SLa+8UieTMGj1xeeDosEZL+zTVpThTAmQ0RdEZM+/R5xQcmj2CWoXNehFChYB0CxDK/0e0Oc5O/Rm6BWUg40VCnvi6k0OfrcZuZYCqwu3IGsjxnXdl5htLMh1EOWeVRHhssWK+ZRdHo24TQHELJPh9qGVzq3k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Xpm1Y66T; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Xpm1Y66T" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0FA5BC32782; Fri, 16 Aug 2024 13:44:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1723815899; bh=1scx8whBOKjnrrkIQ8ohdv6xkBmx+W6qwhZSeMPIvKs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Xpm1Y66ThOLrnOJRBxMGM5ADRmjEy54WH2wKLmswqV2vgWniNui4wjnLxvUdnpvs7 jCFVdECF9nX1GEoPTmqc2oy9stCd594ABhClYNW8BDZ/ZpLqfe38S25nmsNUlbb2xe ZTL5h5CJD5ThouOePrAmZwzWDKTD2B6lV3Ijjm5+A9uRYEI3YAvYperaZlQBs9xNzq MmugEX7tGnE7UIAaus1Gy4ZXpJz4TrmWU9oyunofz6VepUn783O8XynP5fMv7HxyfS CZ2901mBBwdu5FXutwjmYlEihlaiXa/u5FnCeotqzL4XEfEPcuF1m93ehDSpAKK+k5 Ybj6xVBd+atgg== From: Alexey Gladkov To: linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev Cc: "Alexey Gladkov (Intel)" , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , "H. Peter Anvin" , "Kirill A. Shutemov" , Andrew Morton , Yuan Yao , Geert Uytterhoeven , Yuntao Wang , Kai Huang , Baoquan He , Oleg Nesterov , cho@microsoft.com, decui@microsoft.com, John.Starks@microsoft.com Subject: [PATCH v3 02/10] x86/tdx: Add validation of userspace MMIO instructions Date: Fri, 16 Aug 2024 15:43:52 +0200 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Alexey Gladkov (Intel)" Instructions from kernel space are considered trusted. If the MMIO instruction is from userspace it must be checked. For userspace instructions, it is need to check that the INSN has not changed at the time of #VE and before the execution of the instruction. Once the userspace instruction parsed is enforced that the address points to mapped memory of current process and that address does not point to private memory. After parsing the userspace instruction, it is necessary to ensure that: 1. the operation direction (read/write) corresponds to #VE info; 2. the address still points to mapped memory of current process; 3. the address does not point to private memory. Signed-off-by: Alexey Gladkov (Intel) --- arch/x86/coco/tdx/tdx.c | 128 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 115 insertions(+), 13 deletions(-) diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index af0b6c1cacf7..86c22fec97fb 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -405,6 +406,84 @@ static bool mmio_write(int size, unsigned long addr, u= nsigned long val) EPT_WRITE, addr, val); } =20 +static inline bool is_private_gpa(u64 gpa) +{ + return gpa =3D=3D cc_mkenc(gpa); +} + +static int get_phys_addr(unsigned long addr, phys_addr_t *phys_addr, bool = *writable) +{ + unsigned int level; + pgd_t *pgdp; + pte_t *ptep; + + /* + * Address validation only makes sense for a user process. The lock must + * be obtained before validation can begin. + */ + mmap_assert_locked(current->mm); + + pgdp =3D pgd_offset(current->mm, addr); + + if (!pgd_none(*pgdp)) { + ptep =3D lookup_address_in_pgd(pgdp, addr, &level); + if (ptep) { + unsigned long offset; + + offset =3D addr & ~page_level_mask(level); + *phys_addr =3D PFN_PHYS(pte_pfn(*ptep)); + *phys_addr |=3D offset; + + *writable =3D pte_write(*ptep); + + return 0; + } + } + + return -EFAULT; +} + +static int valid_vaddr(struct ve_info *ve, enum insn_mmio_type mmio, int s= ize, + unsigned long vaddr) +{ + phys_addr_t phys_addr; + bool writable =3D false; + + /* It's not fatal. This can happen due to swap out or page migration. */ + if (get_phys_addr(vaddr, &phys_addr, &writable) || (ve->gpa !=3D cc_mkdec= (phys_addr))) + return -EAGAIN; + + /* + * Re-check whether #VE info matches the instruction that was decoded. + * + * The ve->gpa was valid at the time ve_info was received. But this code + * executed with interrupts enabled, allowing tlb shootdown and therefore + * munmap() to be executed in the parallel thread. + * + * By the time MMIO emulation is performed, ve->gpa may be already + * unmapped from the process, the device it belongs to removed from + * system and something else could be plugged in its place. + */ + switch (mmio) { + case INSN_MMIO_WRITE: + case INSN_MMIO_WRITE_IMM: + if (!writable || !(ve->exit_qual & EPT_VIOLATION_ACC_WRITE)) + return -EFAULT; + break; + case INSN_MMIO_READ: + case INSN_MMIO_READ_ZERO_EXTEND: + case INSN_MMIO_READ_SIGN_EXTEND: + if (!(ve->exit_qual & EPT_VIOLATION_ACC_READ)) + return -EFAULT; + break; + default: + WARN_ONCE(1, "Unsupported mmio instruction: %d", mmio); + return -EINVAL; + } + + return 0; +} + static int handle_mmio_write(struct insn *insn, enum insn_mmio_type mmio, = int size, struct pt_regs *regs, struct ve_info *ve) { @@ -489,7 +568,7 @@ static int handle_mmio(struct pt_regs *regs, struct ve_= info *ve) enum insn_mmio_type mmio; struct insn insn =3D {}; unsigned long vaddr; - int size; + int size, ret; =20 /* Only in-kernel MMIO is supported */ if (WARN_ON_ONCE(user_mode(regs))) @@ -505,6 +584,17 @@ static int handle_mmio(struct pt_regs *regs, struct ve= _info *ve) if (WARN_ON_ONCE(mmio =3D=3D INSN_MMIO_DECODE_FAILED)) return -EINVAL; =20 + vaddr =3D (unsigned long)insn_get_addr_ref(&insn, regs); + + if (current->mm) { + if (mmap_read_lock_killable(current->mm)) + return -EINTR; + + ret =3D valid_vaddr(ve, mmio, size, vaddr); + if (ret) + goto unlock; + } + /* * Reject EPT violation #VEs that split pages. * @@ -514,30 +604,39 @@ static int handle_mmio(struct pt_regs *regs, struct v= e_info *ve) * * load_unaligned_zeropad() will recover using exception fixups. */ - vaddr =3D (unsigned long)insn_get_addr_ref(&insn, regs); - if (vaddr / PAGE_SIZE !=3D (vaddr + size - 1) / PAGE_SIZE) - return -EFAULT; + if (vaddr / PAGE_SIZE !=3D (vaddr + size - 1) / PAGE_SIZE) { + ret =3D -EFAULT; + goto unlock; + } =20 switch (mmio) { case INSN_MMIO_WRITE: case INSN_MMIO_WRITE_IMM: case INSN_MMIO_MOVS: - return handle_mmio_write(&insn, mmio, size, regs, ve); + ret =3D handle_mmio_write(&insn, mmio, size, regs, ve); + break; case INSN_MMIO_READ: case INSN_MMIO_READ_ZERO_EXTEND: case INSN_MMIO_READ_SIGN_EXTEND: - return handle_mmio_read(&insn, mmio, size, regs, ve); + ret =3D handle_mmio_read(&insn, mmio, size, regs, ve); + break; case INSN_MMIO_DECODE_FAILED: /* * MMIO was accessed with an instruction that could not be * decoded or handled properly. It was likely not using io.h * helpers or accessed MMIO accidentally. */ - return -EINVAL; + ret =3D -EINVAL; + break; default: WARN_ONCE(1, "Unknown insn_decode_mmio() decode value?"); - return -EINVAL; + ret =3D -EINVAL; } +unlock: + if (current->mm) + mmap_read_unlock(current->mm); + + return ret; } =20 static bool handle_in(struct pt_regs *regs, int size, int port) @@ -681,11 +780,6 @@ static int virt_exception_user(struct pt_regs *regs, s= truct ve_info *ve) } } =20 -static inline bool is_private_gpa(u64 gpa) -{ - return gpa =3D=3D cc_mkenc(gpa); -} - /* * Handle the kernel #VE. * @@ -723,6 +817,14 @@ bool tdx_handle_virt_exception(struct pt_regs *regs, s= truct ve_info *ve) insn_len =3D virt_exception_user(regs, ve); else insn_len =3D virt_exception_kernel(regs, ve); + + /* + * A special case to return to userspace without increasing regs->ip + * to repeat the instruction once again. + */ + if (insn_len =3D=3D -EAGAIN) + return true; + if (insn_len < 0) return false; =20 --=20 2.45.2 From nobody Tue Feb 10 03:01:59 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A4E091BDAA7; Fri, 16 Aug 2024 13:45:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815904; cv=none; b=TfxArKuFyUWYt7cFCIu3oY8ekDfGpM6G0PoiEOc/BIPKvDhPUTdBu+OP08KYZtwkFEwDqjG2KPJdQ9f8IukKMrQyjV26x3xB73oLpwWIYlk4f9Xs2oYgyMW3IBI8r14FIVaWzB05+TJO99t5wBJOaz2Q+Pt87cSu2WkSMnFJD3M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815904; c=relaxed/simple; bh=hvzqcn28E3scaeuRjxnr8MAC0MN2MjYYCtSOK+Ib1v8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=J7ikNMXbOdfu54SVm8wcLiOmPUHMlCJrc9rzIFdkIsxOnT33FgSb/iilWE0W7uRHhyGOIo57DDDoAb0lecif3SslE1jp2VKnXXi1VSagB6r6/fl9dX3A6v66ldNBLwOAIf0crSo58eQRr4bm5QG2IJJrAQ8ePWQr6WRwB8pcKK8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=TNyuC3l2; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="TNyuC3l2" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 597EAC4AF09; Fri, 16 Aug 2024 13:45:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1723815904; bh=hvzqcn28E3scaeuRjxnr8MAC0MN2MjYYCtSOK+Ib1v8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TNyuC3l2wggg08ER39I7Ih7rSNrN4swhgxoL6SQIBJ2EKR79Si3SAyQXvEmPiqTtp TXY9+66YpZcw20hUahSdhswKPjkCy5XJhWcld1TD2dQyyuiNnKnjs1GPp29TCL9Kg2 UgyysDM0R9CDaouZtM6o5oMmY+qdKJGAcOuCAYkn5ZRqP+MS7dC0OCNaf/FqnwtiVN +MEXuh+P9NrKSLRC4f1f+o79zMcfP6M0fH378PEx+NY27zJuC43swqc6Qb+gRR8Zym uKfyMGvdWB3SoOMRI3Q4Y2GlmqYx0FdbTlCUiW0YJVZXPKdzOqJ+twbww8lfk7INrb QDeKZLK7CkWFw== From: Alexey Gladkov To: linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev Cc: "Alexey Gladkov (Intel)" , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , "H. Peter Anvin" , "Kirill A. Shutemov" , Andrew Morton , Yuan Yao , Geert Uytterhoeven , Yuntao Wang , Kai Huang , Baoquan He , Oleg Nesterov , cho@microsoft.com, decui@microsoft.com, John.Starks@microsoft.com Subject: [PATCH v3 03/10] x86/tdx: Allow MMIO from userspace Date: Fri, 16 Aug 2024 15:43:53 +0200 Message-ID: <2a79d86c268d934644b8e4a5a8c59b4699fa0015.1723807851.git.legion@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Alexey Gladkov (Intel)" The MMIO emulation is only allowed for kernel space code. It is carried out through a special API, which uses only certain instructions. This does not allow userspace to work with virtual devices. Allow userspace to use the same instructions as kernel space to access MMIO. So far, no additional checks have been made. Signed-off-by: Alexey Gladkov (Intel) Reviewed-by: Kirill A. Shutemov --- arch/x86/coco/tdx/tdx.c | 43 +++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index 86c22fec97fb..254d5293d25a 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -484,6 +484,32 @@ static int valid_vaddr(struct ve_info *ve, enum insn_m= mio_type mmio, int size, return 0; } =20 +static int decode_insn_struct(struct insn *insn, struct pt_regs *regs) +{ + char buffer[MAX_INSN_SIZE]; + + if (user_mode(regs)) { + int nr_copied =3D insn_fetch_from_user(regs, buffer); + + if (nr_copied <=3D 0) + return -EFAULT; + + if (!insn_decode_from_regs(insn, regs, buffer, nr_copied)) + return -EINVAL; + } else { + if (copy_from_kernel_nofault(buffer, (void *)regs->ip, MAX_INSN_SIZE)) + return -EFAULT; + + if (insn_decode(insn, buffer, MAX_INSN_SIZE, INSN_MODE_64)) + return -EINVAL; + } + + if (!insn->immediate.got) + return -EINVAL; + + return 0; +} + static int handle_mmio_write(struct insn *insn, enum insn_mmio_type mmio, = int size, struct pt_regs *regs, struct ve_info *ve) { @@ -564,21 +590,14 @@ static int handle_mmio_read(struct insn *insn, enum i= nsn_mmio_type mmio, int siz =20 static int handle_mmio(struct pt_regs *regs, struct ve_info *ve) { - char buffer[MAX_INSN_SIZE]; enum insn_mmio_type mmio; struct insn insn =3D {}; unsigned long vaddr; int size, ret; =20 - /* Only in-kernel MMIO is supported */ - if (WARN_ON_ONCE(user_mode(regs))) - return -EFAULT; - - if (copy_from_kernel_nofault(buffer, (void *)regs->ip, MAX_INSN_SIZE)) - return -EFAULT; - - if (insn_decode(&insn, buffer, MAX_INSN_SIZE, INSN_MODE_64)) - return -EINVAL; + ret =3D decode_insn_struct(&insn, regs); + if (ret) + return ret; =20 mmio =3D insn_decode_mmio(&insn, &size); if (WARN_ON_ONCE(mmio =3D=3D INSN_MMIO_DECODE_FAILED)) @@ -774,6 +793,10 @@ static int virt_exception_user(struct pt_regs *regs, s= truct ve_info *ve) switch (ve->exit_reason) { case EXIT_REASON_CPUID: return handle_cpuid(regs, ve); + case EXIT_REASON_EPT_VIOLATION: + if (is_private_gpa(ve->gpa)) + panic("Unexpected EPT-violation on private memory."); + return handle_mmio(regs, ve); default: pr_warn("Unexpected #VE: %lld\n", ve->exit_reason); return -EIO; --=20 2.45.2 From nobody Tue Feb 10 03:01:59 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 68B251AD41D; Fri, 16 Aug 2024 13:45:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815909; cv=none; b=brIh6KFUbO1KaIZLpP6QG003gWIRULEKOyhqmx9yoOnuTNbrdI8EO0go8c1+LO9R+yoIcHWfq4aOIXkjB3D2TwgM0b7PgUn8syzE8uWlucrEq2eNjZHLcAzU4C5d70kD1zu+1Hm81bnkG0CmQ8amUtZWkJjpT3hSBHZMrfW5g6Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815909; c=relaxed/simple; bh=UmfOwHRSoQh66VG7xeNgJsIpyeVJCPweXU97i/kW76g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=US4c6Ca7rHSezezR1jM3PQQe+a+CCPP9H2mFx/kVwX/xVNvGOCysRMFDVlVD5wFAbLFYXjc0xznMiyPgdoZuTYHYqtCCwt7Oj4jua/r1ZjhwtTbJjF0eDLs1fhknLFZ+DckgvokzLHZw9UbgfBPQUzjClMsMO3BvGjyJ8li7zeo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=LJ2oiF6i; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="LJ2oiF6i" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A1CEAC4AF0C; Fri, 16 Aug 2024 13:45:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1723815909; bh=UmfOwHRSoQh66VG7xeNgJsIpyeVJCPweXU97i/kW76g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LJ2oiF6ibBfEWVue4Wx+zaW1OlnkoVUo+A/tsYDxA9Lgi685PXJLGDIZqJJqm0/yK FVcVhK9DXQf+NH1jW9az5sQ9I1qIwcxQQIBgPiej/kMtLOqEOxXoZq4Qi8xz8Vaeai 0JAFiUqcnfJDP10gKU3Sw9X/L4PaqoEIXf8H90eyHE4d18LZ6lRPallGwzqicZz2zX hF8A+CENcOfAhw/sqN2EKJ6wd1err2DI3txRvEILNI0+yKwaEM3hSrxTWqaCYlwvYH 4XbPkhuL54H/IWkLlFWOcpRCMC68ZCKZyTnDmehIJErfBM3YB6pgYFlibC0+lLTVIb QVRudgm5G7KWQ== From: Alexey Gladkov To: linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev Cc: "Alexey Gladkov (Intel)" , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , "H. Peter Anvin" , "Kirill A. Shutemov" , Andrew Morton , Yuan Yao , Geert Uytterhoeven , Yuntao Wang , Kai Huang , Baoquan He , Oleg Nesterov , Tom Lendacky , Kevin Loughlin , Nikunj A Dadhania , cho@microsoft.com, decui@microsoft.com, John.Starks@microsoft.com Subject: [PATCH v3 04/10] x86/insn: Read and decode insn without crossing the page boundary Date: Fri, 16 Aug 2024 15:43:54 +0200 Message-ID: <9704da6a35d62932d464d33b39953fc5b2fd74ea.1723807851.git.legion@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Alexey Gladkov (Intel)" In case the instruction is close to the page boundary, reading MAX_INSN_SIZE may cross the page boundary. The second page might be from a different VMA and reading can have side effects. The problem is that the actual size of the instruction is not known. The solution might be to try read the data to the end of the page and try parse it in the hope that the instruction is smaller than the maximum buffer size. Co-developed-by: Kirill A. Shutemov Signed-off-by: Kirill A. Shutemov Signed-off-by: Alexey Gladkov (Intel) --- arch/x86/include/asm/insn-eval.h | 15 +++++++++ arch/x86/lib/insn-eval.c | 55 ++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/arch/x86/include/asm/insn-eval.h b/arch/x86/include/asm/insn-e= val.h index 54368a43abf6..160e483bde99 100644 --- a/arch/x86/include/asm/insn-eval.h +++ b/arch/x86/include/asm/insn-eval.h @@ -32,6 +32,21 @@ int insn_fetch_from_user_inatomic(struct pt_regs *regs, bool insn_decode_from_regs(struct insn *insn, struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE], int buf_size); =20 +int insn_fetch_decode_from_user_common(struct insn *insn, struct pt_regs *= regs, + bool inatomic); + +static inline int insn_fetch_decode_from_user(struct insn *insn, + struct pt_regs *regs) +{ + return insn_fetch_decode_from_user_common(insn, regs, false); +} + +static inline int insn_fetch_decode_from_user_inatomic(struct insn *insn, + struct pt_regs *regs) +{ + return insn_fetch_decode_from_user_common(insn, regs, true); +} + enum insn_mmio_type { INSN_MMIO_DECODE_FAILED, INSN_MMIO_WRITE, diff --git a/arch/x86/lib/insn-eval.c b/arch/x86/lib/insn-eval.c index 98631c0e7a11..67bfb645df67 100644 --- a/arch/x86/lib/insn-eval.c +++ b/arch/x86/lib/insn-eval.c @@ -1668,3 +1668,58 @@ enum insn_mmio_type insn_decode_mmio(struct insn *in= sn, int *bytes) =20 return type; } + +/** + * insn_fetch_decode_from_user_common() - Copy and decode instruction bytes + * from user-space memory + * @buf: Array to store the fetched instruction + * @regs: Structure with register values as seen when entering kernel mode + * @inatomic boolean flag whether function is used in atomic context + * + * Gets the linear address of the instruction and copies the instruction b= ytes + * and decodes the instruction. + * + * Returns: + * + * - 0 on success. + * - -EFAULT if the copy from userspace fails. + * - -EINVAL if the linear address of the instruction could not be calcula= ted. + */ +int insn_fetch_decode_from_user_common(struct insn *insn, struct pt_regs *= regs, + bool inatomic) +{ + char buffer[MAX_INSN_SIZE]; + int nr_copied, size; + unsigned long ip; + + if (insn_get_effective_ip(regs, &ip)) + return -EINVAL; + + /* + * On the first attempt, read up to MAX_INSN_SIZE, but do not cross a + * page boundary. The second page might be from a different VMA and + * reading can have side effects (i.e. reading from MMIO). + */ + size =3D min(MAX_INSN_SIZE, PAGE_SIZE - offset_in_page(ip)); +retry: + nr_copied =3D size; + + if (inatomic) + nr_copied -=3D __copy_from_user_inatomic(buffer, (void __user *)ip, size= ); + else + nr_copied -=3D copy_from_user(buffer, (void __user *)ip, size); + + if (nr_copied <=3D 0) + return -EFAULT; + + if (!insn_decode_from_regs(insn, regs, buffer, nr_copied)) { + /* If decode failed, try to copy across page boundary */ + if (size < MAX_INSN_SIZE) { + size =3D MAX_INSN_SIZE; + goto retry; + } + return -EINVAL; + } + + return 0; +} --=20 2.45.2 From nobody Tue Feb 10 03:01:59 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D13811BCA0F; Fri, 16 Aug 2024 13:45:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815913; cv=none; b=kE+Vg5HmRYhxgOJR0VMcO3bCmm4/YOj3SJoe3R8GsJs5CyeI6bBW9vi23tSWn7AGgqbWti6mTKFjPq8RTn5ZYIoQQ+MRVtL7JA0xj9/w48HBRpU50fGt3BO+4tPtxGP4NMR22YMFnxypFkYcPphYZ/sXZyMbJzJEHNimR+PXf84= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815913; c=relaxed/simple; bh=oJ8jrbxrXllrr3ZEDRdUWjb+RVr3kNxWUfwyQ6lqK3c=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=E9BULfa9Aur8N6jFkGw64+okcfHmONKjsZ2csLuAhhTsB0nIy7entt1m24zzYg6ajA7T3/bxLYW9Y+YACMbPXkqZO8aLFJVqrPdZzcMWGewTohXgYTff7h8Llvoj5s888t0DClhtFSXpWwzSii+6q2NkZ/z5iEBMV+QHhPw/bKs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=j8uOsuos; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="j8uOsuos" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 81EB3C4AF0D; Fri, 16 Aug 2024 13:45:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1723815913; bh=oJ8jrbxrXllrr3ZEDRdUWjb+RVr3kNxWUfwyQ6lqK3c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=j8uOsuosgUzB57cIEOdqWGZUiiOyFB7cwQsfujFIiTRK3EuKyRA2iFRQy/8WImsKK dPJo8wU55kBxBnFECbZHWi40x8ssj+VMJpJQR9A6uLEEAIlwIiI0QWYlFpJDmgQpzi 8jcm102O2Ldyl9C+uN8bDpkqQ+CMrKb8rIHWZBLGLi5XVuYsQYOq0VgfBzmMpHNKWt SjZ/OOSL0y1kSDSk+4oTkCrVyeBV5ZfCPNZKehzEXeBNMcfmNEAx6d3yH8m5v3XtAF 46k0Z4U7fxUtF7ChMCx11jqztGD3FWwq7kmiX4ozVxjx7TD7/bIW8+xx/U/SKewjnZ H9AfqF0/ZLkrg== From: Alexey Gladkov To: linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev Cc: "Alexey Gladkov (Intel)" , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , "H. Peter Anvin" , "Kirill A. Shutemov" , Andrew Morton , Yuan Yao , Geert Uytterhoeven , Yuntao Wang , Kai Huang , Baoquan He , Oleg Nesterov , cho@microsoft.com, decui@microsoft.com, John.Starks@microsoft.com Subject: [PATCH v3 05/10] x86/tdx: Avoid crossing the page boundary Date: Fri, 16 Aug 2024 15:43:55 +0200 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Alexey Gladkov (Intel)" Try to avoid crossing the page boundary to avoid side effects if the next page belongs to another VMA. Signed-off-by: Alexey Gladkov (Intel) --- arch/x86/coco/tdx/tdx.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index 254d5293d25a..e3d692342603 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -489,13 +489,10 @@ static int decode_insn_struct(struct insn *insn, stru= ct pt_regs *regs) char buffer[MAX_INSN_SIZE]; =20 if (user_mode(regs)) { - int nr_copied =3D insn_fetch_from_user(regs, buffer); + int ret =3D insn_fetch_decode_from_user(insn, regs); =20 - if (nr_copied <=3D 0) - return -EFAULT; - - if (!insn_decode_from_regs(insn, regs, buffer, nr_copied)) - return -EINVAL; + if (ret) + return ret; } else { if (copy_from_kernel_nofault(buffer, (void *)regs->ip, MAX_INSN_SIZE)) return -EFAULT; --=20 2.45.2 From nobody Tue Feb 10 03:01:59 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BADF11BCA0F; Fri, 16 Aug 2024 13:45:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815918; cv=none; b=SDwSWNCGGf9CcGF2sp92EEjM4R85vDemufqDkLNgdkcVlV0IQ0dVil/BAdDZ0Pt4osgSDDVQoOyOAoLlroQF7MButS62wumDiG2JLztDJGBOTz1DWn/wPdF2icsIl4TiUvXF3YJGUE2bBiiSXLo8o4ImFJpl4/oMg0xmdVGUy00= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815918; c=relaxed/simple; bh=P2CiZHuj4n0wzBrGJeq7xdgx8UuuSPVLHbtVZzRm6cM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dXXeNoQV4Xwl2J3zjoRBOuOM2YEhZKbE3SHiyt9GdbZ+nkfL717cdv51h69A4Eo98Ofo8oAw1PKlgJ9YC8CXCaOimKBmrjxLkqhxVDjdxJ0yTKutJqkqNsQ0YAXDYVemNkuqk1SZVPvmK1nHEgbDN7lpxjB7bzSU0TnhGaeUmb8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=rLVrfZ3R; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="rLVrfZ3R" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CF185C4AF09; Fri, 16 Aug 2024 13:45:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1723815918; bh=P2CiZHuj4n0wzBrGJeq7xdgx8UuuSPVLHbtVZzRm6cM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rLVrfZ3RCQJY48FPpnHaSf248JkZQZNJFlsMdKa69x6kAZjmJs6VwIQYzGK5eewXG seav76X05XpPe01S3Wj43mBfTVsm18RCtDA3T0YiwOTkxrHwgo7DkWUzhHdCsmKIsN pH1+bhc93xNgWdGqWR8LdYoSnjB4gIvAOD2cHS0tEL3anMdTJdXYSGYxhwTS85SkgC fK1ya7EJoKmX5AnmJXNB4oM5yVZh2vRj33RKu4kMG/mSLgODNNhYM0Le9nYnJrY2Es fD2igF4fIySpwIKyX1SQnDDyHeG/iCtd4pwNFJ/5zkNIjGTjeVemkRGomHZyhD3APU Hs2MbuZLBCQIg== From: Alexey Gladkov To: linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev Cc: "Alexey Gladkov (Intel)" , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , "H. Peter Anvin" , "Kirill A. Shutemov" , Andrew Morton , Yuan Yao , Geert Uytterhoeven , Yuntao Wang , Kai Huang , Baoquan He , Oleg Nesterov , Tom Lendacky , Kevin Loughlin , Nikunj A Dadhania , cho@microsoft.com, decui@microsoft.com, John.Starks@microsoft.com Subject: [PATCH v3 06/10] x86/sev: Avoid crossing the page boundary Date: Fri, 16 Aug 2024 15:43:56 +0200 Message-ID: <56607a180717a4196738224c995fa2c16af44da2.1723807851.git.legion@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Alexey Gladkov (Intel)" Try to avoid crossing the page boundary to avoid side effects if the next page belongs to another VMA. Signed-off-by: Alexey Gladkov (Intel) --- arch/x86/coco/sev/core.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c index 082d61d85dfc..b0e8e4264464 100644 --- a/arch/x86/coco/sev/core.c +++ b/arch/x86/coco/sev/core.c @@ -311,17 +311,16 @@ static int vc_fetch_insn_kernel(struct es_em_ctxt *ct= xt, =20 static enum es_result __vc_decode_user_insn(struct es_em_ctxt *ctxt) { - char buffer[MAX_INSN_SIZE]; - int insn_bytes; + int ret; =20 - insn_bytes =3D insn_fetch_from_user_inatomic(ctxt->regs, buffer); - if (insn_bytes =3D=3D 0) { + ret =3D insn_fetch_decode_from_user_inatomic(&ctxt->insn, ctxt->regs); + if (ret =3D=3D -EFAULT) { /* Nothing could be copied */ ctxt->fi.vector =3D X86_TRAP_PF; ctxt->fi.error_code =3D X86_PF_INSTR | X86_PF_USER; ctxt->fi.cr2 =3D ctxt->regs->ip; return ES_EXCEPTION; - } else if (insn_bytes =3D=3D -EINVAL) { + } else if (ret =3D=3D -EINVAL) { /* Effective RIP could not be calculated */ ctxt->fi.vector =3D X86_TRAP_GP; ctxt->fi.error_code =3D 0; @@ -329,9 +328,6 @@ static enum es_result __vc_decode_user_insn(struct es_e= m_ctxt *ctxt) return ES_EXCEPTION; } =20 - if (!insn_decode_from_regs(&ctxt->insn, ctxt->regs, buffer, insn_bytes)) - return ES_DECODE_FAILED; - if (ctxt->insn.immediate.got) return ES_OK; else --=20 2.45.2 From nobody Tue Feb 10 03:01:59 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A4CED1BD016; Fri, 16 Aug 2024 13:45:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815922; cv=none; b=uezrNj4ui/8TQS6e1E+yGYbMa2koTf2MMfWO7a6n0R9o8ESmR75lFx3WI5t6aoxuX058VvPPTKb5lizXQI8j3cXsffftkp1QyWIgz4VSkxLs6VebC9Az7oXSZ0aG+qVFHa8KZTkcNzoJpFmn41ZZ2USQzsgX1plG2/YJyDMEPlk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815922; c=relaxed/simple; bh=Ts5tF9pWXXxmeyRHAlmbZkS/2Bgc9tMgGvi92mLtYz4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=HGjuPll2D0+oaosZ53HU+dKiVEdXI+ZE/ClnlcKM6mVhTYBixksTt1SdCKBfxW/T9phxYH6znMZ47rguL9f4+fGtWxh2ifJ9H7Fr9bYGrPl7dWN/pMyCjAFav9m7yJKdkLSF/HsaOxLvj4MqH4ekCn/x9Q1Ik4RMVUDy9aeqtm8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=WHud0r+o; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="WHud0r+o" Received: by smtp.kernel.org (Postfix) with ESMTPSA id ADB2FC4AF0C; Fri, 16 Aug 2024 13:45:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1723815922; bh=Ts5tF9pWXXxmeyRHAlmbZkS/2Bgc9tMgGvi92mLtYz4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WHud0r+okm3N6FjkCgg/XwzOemV7DxbyOQXvcaQ86HbygRd13vVeAVkzMaUE26uq2 onckVAxD3tGdSKBh89EFmLOuzIapFX+kXZhuTC1EPsuDn8irjLWazBrunkjNpNdcQk zq7XHRzz/9rNtIzl4AbT6xhsAiZGzVjHhxA54MSJ6vvD2wBM/ojNNicBh52s5W786a 1mORVj2CQ/yC7XGYeAVUWrv9HyF/AlPnNmRvtlMWsSt7vTqCnEobK+TzPGV0TSR6kT l/lhsem30/0kIKqg4m8cTdikbKrPg68oQxRnPuGqWzqR7xMUtkyj3RVw8C5fn7U/T9 0k3ItHB92eKHA== From: Alexey Gladkov To: linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev Cc: "Alexey Gladkov (Intel)" , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , "H. Peter Anvin" , "Kirill A. Shutemov" , Andrew Morton , Yuan Yao , Geert Uytterhoeven , Yuntao Wang , Kai Huang , Baoquan He , Oleg Nesterov , cho@microsoft.com, decui@microsoft.com, John.Starks@microsoft.com Subject: [PATCH v3 07/10] x86/umip: Avoid crossing the page boundary Date: Fri, 16 Aug 2024 15:43:57 +0200 Message-ID: <5bb84bce0c798a76a318a38e1bb827af10ecaefd.1723807851.git.legion@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Alexey Gladkov (Intel)" Try to avoid crossing the page boundary to avoid side effects if the next page belongs to another VMA. Signed-off-by: Alexey Gladkov (Intel) --- arch/x86/kernel/umip.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/arch/x86/kernel/umip.c b/arch/x86/kernel/umip.c index 5a4b21389b1d..e85c3cafc258 100644 --- a/arch/x86/kernel/umip.c +++ b/arch/x86/kernel/umip.c @@ -338,7 +338,6 @@ bool fixup_umip_exception(struct pt_regs *regs) int nr_copied, reg_offset, dummy_data_size, umip_inst; /* 10 bytes is the maximum size of the result of UMIP instructions */ unsigned char dummy_data[10] =3D { 0 }; - unsigned char buf[MAX_INSN_SIZE]; unsigned long *reg_addr; void __user *uaddr; struct insn insn; @@ -350,11 +349,7 @@ bool fixup_umip_exception(struct pt_regs *regs) * Give up on emulation if fetching the instruction failed. Should a * page fault or a #GP be issued? */ - nr_copied =3D insn_fetch_from_user(regs, buf); - if (nr_copied <=3D 0) - return false; - - if (!insn_decode_from_regs(&insn, regs, buf, nr_copied)) + if (insn_fetch_decode_from_user(&insn, regs)) return false; =20 umip_inst =3D identify_insn(&insn); --=20 2.45.2 From nobody Tue Feb 10 03:01:59 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2F49F1BD02A; Fri, 16 Aug 2024 13:45:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815927; cv=none; b=FAnVpRGnDIeChAM+iZVjxoEiPRrXA7HCq4qzfABlKnj7LCwVDKamdsfywbWjHLvALwU9GUeKoLwVtP8QzmqTb+7hqnkSuOtL3AV8eLkqJQjoNIcUh7igeH2v5pAky2G6mMgshni5vgxSjwMuFokxUNMyPeLtP7GIKAqoD+y6EbU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815927; c=relaxed/simple; bh=fWwOfudJtdwdjI/VfKTv2mK20greegDMKRi2pde9jE4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=qVMniI40vhAGjfylW36GNxlTRjIobkts3TVy69kAPRD8dVD/OQCVsUMt8e2mD/6ddG9cbSdoItDYvXrQbI58V8ztj/Lj1K2w0xHCRlag3e8/5lbtNVrwlJDZgOp8c5aSBA38eUEkkkktDFhBubhL0Mnq+cSr+J1qf3CKhbB4sK0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=qF1dMihl; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="qF1dMihl" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 01364C32782; Fri, 16 Aug 2024 13:45:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1723815926; bh=fWwOfudJtdwdjI/VfKTv2mK20greegDMKRi2pde9jE4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qF1dMihlaeFZyRaL7rG8ySi2nOSxwWEk62XyuOoWIKniyf5MJhdn9Mt7vcCBnyfUQ FNkyJ4kpGSMClMbp75Mrc46dJFy6m9llqGJSG+xWcS9b5kktEIR9gktiMvhoxs/2oP of48Q6zi50VDRsa2NR7dQ8yc3Pg936pUfm/HUpvzME8JEzlCvJK+/5rz6oFUCFkooi MSkRfjMKXPPGRYzNYE6Es42tbxHy1YqHYrTdkj6nVvT2xJb3Er6a6NKkv5rhLkmj8g FKSObC8hxqSDESel8NQlMa/Kw7CyJlPNCRzXFsQFeczHAQxcaQ8lXXdTy0q0Eq5OP8 0zizwPXiKb+Ew== From: Alexey Gladkov To: linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev Cc: "Alexey Gladkov (Intel)" , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , "H. Peter Anvin" , "Kirill A. Shutemov" , Andrew Morton , Yuan Yao , Geert Uytterhoeven , Yuntao Wang , Kai Huang , Baoquan He , Oleg Nesterov , cho@microsoft.com, decui@microsoft.com, John.Starks@microsoft.com Subject: [PATCH v3 08/10] x86/tdx: Add a restriction on access to MMIO address Date: Fri, 16 Aug 2024 15:43:58 +0200 Message-ID: <7a4c51f7ccd11c3197f05a1affd6fdbcfad6baad.1723807851.git.legion@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Alexey Gladkov (Intel)" In the case of userspace MMIO, if the user instruction + MAX_INSN_SIZE straddles page, then the "fetch" in the kernel could trigger a #VE. In this case the kernel would handle this second #VE as a !user_mode() MMIO. That way, additional address verifications can be avoided. The scenario of accessing userspace MMIO addresses from kernelspace does not seem appropriate under normal circumstances. Until there is a specific usecase for such a scenario it can be disabled. Signed-off-by: Alexey Gladkov (Intel) --- arch/x86/coco/tdx/tdx.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index e3d692342603..94541ee724db 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -411,6 +411,11 @@ static inline bool is_private_gpa(u64 gpa) return gpa =3D=3D cc_mkenc(gpa); } =20 +static inline bool is_kernel_addr(unsigned long addr) +{ + return (long)addr < 0; +} + static int get_phys_addr(unsigned long addr, phys_addr_t *phys_addr, bool = *writable) { unsigned int level; @@ -592,6 +597,7 @@ static int handle_mmio(struct pt_regs *regs, struct ve_= info *ve) unsigned long vaddr; int size, ret; =20 + ret =3D decode_insn_struct(&insn, regs); if (ret) return ret; @@ -600,6 +606,11 @@ static int handle_mmio(struct pt_regs *regs, struct ve= _info *ve) if (WARN_ON_ONCE(mmio =3D=3D INSN_MMIO_DECODE_FAILED)) return -EINVAL; =20 + if (!user_mode(regs) && !is_kernel_addr(ve->gla)) { + WARN_ONCE(1, "Access to userspace address is not supported"); + return -EINVAL; + } + vaddr =3D (unsigned long)insn_get_addr_ref(&insn, regs); =20 if (current->mm) { --=20 2.45.2 From nobody Tue Feb 10 03:01:59 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8E5301BD02A; Fri, 16 Aug 2024 13:45:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815931; cv=none; b=Hzp+bmjRonNfGal7TeDKJlasUYYbI9DZ+pUksp3InU5ANnLB76aykHwgjTg94vBVd1UmkealftkiT9G3+dev/IEsI1mK9RtUZvrkNS9uZPXfAMwJarHcqlaZnQTvfxIulSO/72W9v4uEKiuNiA0UNFt+Y6CYEPBxCyoCv3EeqwE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815931; c=relaxed/simple; bh=fcginaaNpItD9m5GPZr5oEG2nrqWphw68B7KM4hv6iA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YjRv60yLOUn3tiEZs8VemCFt/MSF2Z6DYa5j6zP3teTLxfuPzkMZbnYZBhOXOEUH/cSUdGCa3uy3GKtOTKRJagBkxiSCsbs0c6AZmMwFvIaXktNLbU0RGxm9jkQgeuBOu7nzhpaTLfeHAsPajQdMfpNbxvo2TUzPOxcNqRzbj2E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=PRCGExd7; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="PRCGExd7" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 47CFDC4AF0C; Fri, 16 Aug 2024 13:45:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1723815931; bh=fcginaaNpItD9m5GPZr5oEG2nrqWphw68B7KM4hv6iA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PRCGExd786doVkNTo3lB7FLWdJCyPnLX7LfT0/8cvAZph91p0ypec1yYTWh22fbai L/bfT76irsv530lO1ocVFjTiEkZVHXwhk1sBDt/i2OC3y3aS+92F7do7im8lhq4NnT Kmp04nynCcIRkOssiR+KhbyR9bAGxRNAWUIRydt3j1dtFZIh8RVqEymBn8I16xys7r XfgReUX1gVbAVW2QDNHr1kvyORNu1T3/NWNf3SZ22cma1fSygepp9WM2CEbqGqjwyF TsM75p0dB0nax2UWTFWyvm+tEG3Mxf/fsdIakkBNLUDtK7lc5b800q2ME4Oba/aJz0 c08xRxD+Cl8dA== From: Alexey Gladkov To: linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev Cc: "Alexey Gladkov (Intel)" , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , "H. Peter Anvin" , "Kirill A. Shutemov" , Andrew Morton , Yuan Yao , Geert Uytterhoeven , Yuntao Wang , Kai Huang , Baoquan He , Oleg Nesterov , cho@microsoft.com, decui@microsoft.com, John.Starks@microsoft.com Subject: [PATCH v3 09/10] x86/tdx: Move MMIO helpers to common library Date: Fri, 16 Aug 2024 15:43:59 +0200 Message-ID: <5660b8208dc771a6517c40d6448f996efae2768b.1723807851.git.legion@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Alexey Gladkov (Intel)" AMD code has helpers that are used to emulate MOVS instructions. To be able to reuse this code in the MOVS implementation for intel, it is necessary to move them to a common location. Signed-off-by: Alexey Gladkov (Intel) --- arch/x86/coco/sev/core.c | 135 ++++---------------------------------- arch/x86/include/asm/io.h | 3 + arch/x86/lib/iomem.c | 125 +++++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+), 121 deletions(-) diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c index b0e8e4264464..c154d2587c38 100644 --- a/arch/x86/coco/sev/core.c +++ b/arch/x86/coco/sev/core.c @@ -365,72 +365,18 @@ static enum es_result vc_decode_insn(struct es_em_ctx= t *ctxt) static enum es_result vc_write_mem(struct es_em_ctxt *ctxt, char *dst, char *buf, size_t size) { - unsigned long error_code =3D X86_PF_PROT | X86_PF_WRITE; - - /* - * This function uses __put_user() independent of whether kernel or user - * memory is accessed. This works fine because __put_user() does no - * sanity checks of the pointer being accessed. All that it does is - * to report when the access failed. - * - * Also, this function runs in atomic context, so __put_user() is not - * allowed to sleep. The page-fault handler detects that it is running - * in atomic context and will not try to take mmap_sem and handle the - * fault, so additional pagefault_enable()/disable() calls are not - * needed. - * - * The access can't be done via copy_to_user() here because - * vc_write_mem() must not use string instructions to access unsafe - * memory. The reason is that MOVS is emulated by the #VC handler by - * splitting the move up into a read and a write and taking a nested #VC - * exception on whatever of them is the MMIO access. Using string - * instructions here would cause infinite nesting. - */ - switch (size) { - case 1: { - u8 d1; - u8 __user *target =3D (u8 __user *)dst; - - memcpy(&d1, buf, 1); - if (__put_user(d1, target)) - goto fault; - break; - } - case 2: { - u16 d2; - u16 __user *target =3D (u16 __user *)dst; - - memcpy(&d2, buf, 2); - if (__put_user(d2, target)) - goto fault; - break; - } - case 4: { - u32 d4; - u32 __user *target =3D (u32 __user *)dst; + unsigned long error_code; + int ret; =20 - memcpy(&d4, buf, 4); - if (__put_user(d4, target)) - goto fault; - break; - } - case 8: { - u64 d8; - u64 __user *target =3D (u64 __user *)dst; + ret =3D __put_iomem(dst, buf, size); + if (!ret) + return ES_OK; =20 - memcpy(&d8, buf, 8); - if (__put_user(d8, target)) - goto fault; - break; - } - default: - WARN_ONCE(1, "%s: Invalid size: %zu\n", __func__, size); + if (ret =3D=3D -EIO) return ES_UNSUPPORTED; - } =20 - return ES_OK; + error_code =3D X86_PF_PROT | X86_PF_WRITE; =20 -fault: if (user_mode(ctxt->regs)) error_code |=3D X86_PF_USER; =20 @@ -444,71 +390,18 @@ static enum es_result vc_write_mem(struct es_em_ctxt = *ctxt, static enum es_result vc_read_mem(struct es_em_ctxt *ctxt, char *src, char *buf, size_t size) { - unsigned long error_code =3D X86_PF_PROT; - - /* - * This function uses __get_user() independent of whether kernel or user - * memory is accessed. This works fine because __get_user() does no - * sanity checks of the pointer being accessed. All that it does is - * to report when the access failed. - * - * Also, this function runs in atomic context, so __get_user() is not - * allowed to sleep. The page-fault handler detects that it is running - * in atomic context and will not try to take mmap_sem and handle the - * fault, so additional pagefault_enable()/disable() calls are not - * needed. - * - * The access can't be done via copy_from_user() here because - * vc_read_mem() must not use string instructions to access unsafe - * memory. The reason is that MOVS is emulated by the #VC handler by - * splitting the move up into a read and a write and taking a nested #VC - * exception on whatever of them is the MMIO access. Using string - * instructions here would cause infinite nesting. - */ - switch (size) { - case 1: { - u8 d1; - u8 __user *s =3D (u8 __user *)src; - - if (__get_user(d1, s)) - goto fault; - memcpy(buf, &d1, 1); - break; - } - case 2: { - u16 d2; - u16 __user *s =3D (u16 __user *)src; + unsigned long error_code; + int ret; =20 - if (__get_user(d2, s)) - goto fault; - memcpy(buf, &d2, 2); - break; - } - case 4: { - u32 d4; - u32 __user *s =3D (u32 __user *)src; + ret =3D __get_iomem(src, buf, size); + if (!ret) + return ES_OK; =20 - if (__get_user(d4, s)) - goto fault; - memcpy(buf, &d4, 4); - break; - } - case 8: { - u64 d8; - u64 __user *s =3D (u64 __user *)src; - if (__get_user(d8, s)) - goto fault; - memcpy(buf, &d8, 8); - break; - } - default: - WARN_ONCE(1, "%s: Invalid size: %zu\n", __func__, size); + if (ret =3D=3D -EIO) return ES_UNSUPPORTED; - } =20 - return ES_OK; + error_code =3D X86_PF_PROT; =20 -fault: if (user_mode(ctxt->regs)) error_code |=3D X86_PF_USER; =20 diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h index 1d60427379c9..ac01d53466cb 100644 --- a/arch/x86/include/asm/io.h +++ b/arch/x86/include/asm/io.h @@ -402,4 +402,7 @@ static inline void iosubmit_cmds512(void __iomem *dst, = const void *src, } } =20 +int __get_iomem(char *src, char *buf, size_t size); +int __put_iomem(char *src, char *buf, size_t size); + #endif /* _ASM_X86_IO_H */ diff --git a/arch/x86/lib/iomem.c b/arch/x86/lib/iomem.c index 5eecb45d05d5..23179953eb5a 100644 --- a/arch/x86/lib/iomem.c +++ b/arch/x86/lib/iomem.c @@ -2,6 +2,7 @@ #include #include #include +#include =20 #define movs(type,to,from) \ asm volatile("movs" type:"=3D&D" (to), "=3D&S" (from):"0" (to), "1" (from= ):"memory") @@ -124,3 +125,127 @@ void memset_io(volatile void __iomem *a, int b, size_= t c) } } EXPORT_SYMBOL(memset_io); + +int __get_iomem(char *src, char *buf, size_t size) +{ + /* + * This function uses __get_user() independent of whether kernel or user + * memory is accessed. This works fine because __get_user() does no + * sanity checks of the pointer being accessed. All that it does is + * to report when the access failed. + * + * Also, this function runs in atomic context, so __get_user() is not + * allowed to sleep. The page-fault handler detects that it is running + * in atomic context and will not try to take mmap_sem and handle the + * fault, so additional pagefault_enable()/disable() calls are not + * needed. + * + * The access can't be done via copy_from_user() here because + * mmio_read_mem() must not use string instructions to access unsafe + * memory. The reason is that MOVS is emulated by the #VC handler by + * splitting the move up into a read and a write and taking a nested #VC + * exception on whatever of them is the MMIO access. Using string + * instructions here would cause infinite nesting. + */ + switch (size) { + case 1: { + u8 d1, __user *s =3D (u8 __user *)src; + + if (__get_user(d1, s)) + return -EFAULT; + memcpy(buf, &d1, 1); + break; + } + case 2: { + u16 d2, __user *s =3D (u16 __user *)src; + + if (__get_user(d2, s)) + return -EFAULT; + memcpy(buf, &d2, 2); + break; + } + case 4: { + u32 d4, __user *s =3D (u32 __user *)src; + + if (__get_user(d4, s)) + return -EFAULT; + memcpy(buf, &d4, 4); + break; + } + case 8: { + u64 d8, __user *s =3D (u64 __user *)src; + + if (__get_user(d8, s)) + return -EFAULT; + memcpy(buf, &d8, 8); + break; + } + default: + WARN_ONCE(1, "%s: Invalid size: %zu\n", __func__, size); + return -EIO; + } + + return 0; +} + +int __put_iomem(char *dst, char *buf, size_t size) +{ + /* + * This function uses __put_user() independent of whether kernel or user + * memory is accessed. This works fine because __put_user() does no + * sanity checks of the pointer being accessed. All that it does is + * to report when the access failed. + * + * Also, this function runs in atomic context, so __put_user() is not + * allowed to sleep. The page-fault handler detects that it is running + * in atomic context and will not try to take mmap_sem and handle the + * fault, so additional pagefault_enable()/disable() calls are not + * needed. + * + * The access can't be done via copy_to_user() here because + * put_iomem() must not use string instructions to access unsafe + * memory. The reason is that MOVS is emulated by the #VC handler by + * splitting the move up into a read and a write and taking a nested #VC + * exception on whatever of them is the MMIO access. Using string + * instructions here would cause infinite nesting. + */ + switch (size) { + case 1: { + u8 d1, __user *target =3D (u8 __user *)dst; + + memcpy(&d1, buf, 1); + if (__put_user(d1, target)) + return -EFAULT; + break; + } + case 2: { + u16 d2, __user *target =3D (u16 __user *)dst; + + memcpy(&d2, buf, 2); + if (__put_user(d2, target)) + return -EFAULT; + break; + } + case 4: { + u32 d4, __user *target =3D (u32 __user *)dst; + + memcpy(&d4, buf, 4); + if (__put_user(d4, target)) + return -EFAULT; + break; + } + case 8: { + u64 d8, __user *target =3D (u64 __user *)dst; + + memcpy(&d8, buf, 8); + if (__put_user(d8, target)) + return -EFAULT; + break; + } + default: + WARN_ONCE(1, "%s: Invalid size: %zu\n", __func__, size); + return -EIO; + } + + return 0; +} --=20 2.45.2 From nobody Tue Feb 10 03:01:59 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E38F11BF33E; Fri, 16 Aug 2024 13:45:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815936; cv=none; b=uZjGFMmyGrojV2ami7OQGElaRB8XRD9pc6kSz0FfWKvz7ImvANFciXRMhDnoZTsGSLdEVf0cWCEZGHLrZXDomBOGEpW/ijSkyZbtyMMdVyo75cjYAw5ClXRiAABnK9E3etM8IDhWI6H1+WmEDdctmKUisUuaorOjoq1D5vFkeak= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723815936; c=relaxed/simple; bh=J6D/pX0gxICYDzXbUUkRtLzUc3rT8YgO+JQ+TyXNZvk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Y0/bZswOePV+63crapqke3yeUNOvFsaXu/uLdguzjbqX6eEYf4msCK+C7IOFD5tFu2EiCopQhG3r+1F6vHj9Cb4vtXvQDNkhVL85ursWctkxy2e1xQVEnhvXEwtaVdz1tEYO5K2z1yWb501CRyYNhEf6J4SBEyakMRS4t+f5F6M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=sPZFAyUx; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="sPZFAyUx" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 93F05C4AF09; Fri, 16 Aug 2024 13:45:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1723815935; bh=J6D/pX0gxICYDzXbUUkRtLzUc3rT8YgO+JQ+TyXNZvk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sPZFAyUxEjZommVT54ebufc5IxjHNrx7IuukX/2g02Rc6m0m5mvVVC0ju6Msabq10 snnjgvJnzr5sMgRv5ZZBOB62Ac4tdQaA28G9queScqPqlzdDYQNjfKeLSsiMe1HWFj eU2xbmVPoiQiwsArSIKXLWWYnbxzV1W4qxQFZ5w9788iLnZT+ddf/3zHmfMJjz5w40 jbnJqu8SLuCnIYiNv2UWiddc26yea8k5Xqlh1kTBUjUY3FjjZxEQMObooty9p/Yzml M0g+nO5dsJFIlsOkAl2UT6sS2PIS/nAvMkfilJKUQSvuWZZhwr8+5NNX6JB56iVL4d aSsbwRNfBIXbg== From: Alexey Gladkov To: linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev Cc: "Alexey Gladkov (Intel)" , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , "H. Peter Anvin" , "Kirill A. Shutemov" , Andrew Morton , Yuan Yao , Geert Uytterhoeven , Yuntao Wang , Kai Huang , Baoquan He , Oleg Nesterov , cho@microsoft.com, decui@microsoft.com, John.Starks@microsoft.com Subject: [PATCH v3 10/10] x86/tdx: Implement movs for MMIO Date: Fri, 16 Aug 2024 15:44:00 +0200 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Alexey Gladkov (Intel)" Add emulation of the MOVS instruction on MMIO regions. MOVS emulation consists of dividing it into a series of read and write operations, which in turn will be validated separately. Signed-off-by: Alexey Gladkov (Intel) --- arch/x86/coco/tdx/tdx.c | 76 +++++++++++++++++++++++++++++--- arch/x86/include/asm/processor.h | 4 ++ 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index 94541ee724db..d7d762bf53dc 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -512,6 +512,62 @@ static int decode_insn_struct(struct insn *insn, struc= t pt_regs *regs) return 0; } =20 +static int handle_mmio_movs(struct insn *insn, struct pt_regs *regs, int s= ize, struct ve_info *ve) +{ + unsigned long ds_base, es_base; + unsigned char *src, *dst; + unsigned char buffer[8]; + int off, ret; + bool rep; + + /* + * The in-kernel code must use a special API that does not use MOVS. + * If the MOVS instruction is received from in-kernel, then something + * is broken. + */ + if (WARN_ON_ONCE(!user_mode(regs))) + return -EFAULT; + + ds_base =3D insn_get_seg_base(regs, INAT_SEG_REG_DS); + es_base =3D insn_get_seg_base(regs, INAT_SEG_REG_ES); + + if (ds_base =3D=3D -1L || es_base =3D=3D -1L) + return -EINVAL; + + rep =3D insn_has_rep_prefix(insn); + + do { + src =3D ds_base + (unsigned char *) regs->si; + dst =3D es_base + (unsigned char *) regs->di; + + current->thread.mmio_emul =3D (unsigned long) src; + + ret =3D __get_iomem(src, buffer, size); + if (ret) + goto out; + + current->thread.mmio_emul =3D (unsigned long) dst; + + ret =3D __put_iomem(dst, buffer, size); + if (ret) + goto out; + + off =3D (regs->flags & X86_EFLAGS_DF) ? -size : size; + + regs->si +=3D off; + regs->di +=3D off; + + if (rep) + regs->cx -=3D 1; + } while (rep || regs->cx > 0); + + ret =3D insn->length; +out: + current->thread.mmio_emul =3D 0; + + return ret; +} + static int handle_mmio_write(struct insn *insn, enum insn_mmio_type mmio, = int size, struct pt_regs *regs, struct ve_info *ve) { @@ -533,9 +589,8 @@ static int handle_mmio_write(struct insn *insn, enum in= sn_mmio_type mmio, int si return insn->length; case INSN_MMIO_MOVS: /* - * MMIO was accessed with an instruction that could not be - * decoded or handled properly. It was likely not using io.h - * helpers or accessed MMIO accidentally. + * MOVS is processed through higher level emulation which breaks + * this instruction into a sequence of reads and writes. */ return -EINVAL; default: @@ -597,7 +652,6 @@ static int handle_mmio(struct pt_regs *regs, struct ve_= info *ve) unsigned long vaddr; int size, ret; =20 - ret =3D decode_insn_struct(&insn, regs); if (ret) return ret; @@ -606,9 +660,18 @@ static int handle_mmio(struct pt_regs *regs, struct ve= _info *ve) if (WARN_ON_ONCE(mmio =3D=3D INSN_MMIO_DECODE_FAILED)) return -EINVAL; =20 + if (mmio =3D=3D INSN_MMIO_MOVS) + return handle_mmio_movs(&insn, regs, size, ve); + if (!user_mode(regs) && !is_kernel_addr(ve->gla)) { - WARN_ONCE(1, "Access to userspace address is not supported"); - return -EINVAL; + /* + * Access from kernel to userspace addresses is not allowed + * unless it is a nested exception during MOVS emulation. + */ + if (current->thread.mmio_emul !=3D ve->gla || !current->mm) { + WARN_ONCE(1, "Access to userspace address is not supported"); + return -EINVAL; + } } =20 vaddr =3D (unsigned long)insn_get_addr_ref(&insn, regs); @@ -639,7 +702,6 @@ static int handle_mmio(struct pt_regs *regs, struct ve_= info *ve) switch (mmio) { case INSN_MMIO_WRITE: case INSN_MMIO_WRITE_IMM: - case INSN_MMIO_MOVS: ret =3D handle_mmio_write(&insn, mmio, size, regs, ve); break; case INSN_MMIO_READ: diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/proces= sor.h index a75a07f4931f..45136b1b02cc 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -503,6 +503,10 @@ struct thread_struct { struct thread_shstk shstk; #endif =20 +#ifdef CONFIG_INTEL_TDX_GUEST + unsigned long mmio_emul; +#endif + /* Floating point and extended processor state */ struct fpu fpu; /* --=20 2.45.2