From nobody Sun Feb 8 02:26:12 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