Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752362AbdHSAcf (ORCPT ); Fri, 18 Aug 2017 20:32:35 -0400 Received: from mga07.intel.com ([134.134.136.100]:26711 "EHLO mga07.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752236AbdHSA2u (ORCPT ); Fri, 18 Aug 2017 20:28:50 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.41,394,1498546800"; d="scan'208";a="1164119714" From: Ricardo Neri To: Ingo Molnar , Thomas Gleixner , "H. Peter Anvin" , Andy Lutomirski , Borislav Petkov Cc: Peter Zijlstra , Andrew Morton , Brian Gerst , Chris Metcalf , Dave Hansen , Paolo Bonzini , Liang Z Li , Masami Hiramatsu , Huang Rui , Jiri Slaby , Jonathan Corbet , "Michael S. Tsirkin" , Paul Gortmaker , Vlastimil Babka , Chen Yucong , "Ravi V. Shankar" , Shuah Khan , linux-kernel@vger.kernel.org, x86@kernel.org, ricardo.neri@intel.com, Ricardo Neri , Adam Buchbinder , Colin Ian King , Lorenzo Stoakes , Qiaowei Ren , Arnaldo Carvalho de Melo , Adrian Hunter , Kees Cook , Thomas Garnier , Dmitry Vyukov Subject: [PATCH v8 19/28] x86/insn-eval: Add wrapper function for 32 and 64-bit addresses Date: Fri, 18 Aug 2017 17:28:00 -0700 Message-Id: <20170819002809.111312-20-ricardo.neri-calderon@linux.intel.com> X-Mailer: git-send-email 2.13.0 In-Reply-To: <20170819002809.111312-1-ricardo.neri-calderon@linux.intel.com> References: <20170819002809.111312-1-ricardo.neri-calderon@linux.intel.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 4239 Lines: 113 The function insn_get_addr_ref() is capable of handling only 64-bit addresses. A previous commit introduced a function to handle 32-bit addresses. Invoke these two functions from a third wrapper function that calls the appropriate routine based on the address size specified in the instruction structure (obtained by looking at the code segment default address size and the address override prefix, if present). While doing this, rename the original function insn_get_addr_ref() with the more appropriate name get_addr_ref_64(), ensure it is only used for 64-bit addresses and returns a 64-bit error value. Also, since 64-bit addresses are not possible in 32-bit builds, provide a dummy function such case. Cc: Dave Hansen Cc: Adam Buchbinder Cc: Colin Ian King Cc: Lorenzo Stoakes Cc: Qiaowei Ren Cc: Arnaldo Carvalho de Melo Cc: Masami Hiramatsu Cc: Adrian Hunter Cc: Kees Cook Cc: Thomas Garnier Cc: Peter Zijlstra Cc: Borislav Petkov Cc: Dmitry Vyukov Cc: Ravi V. Shankar Cc: x86@kernel.org Signed-off-by: Ricardo Neri --- arch/x86/lib/insn-eval.c | 53 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/arch/x86/lib/insn-eval.c b/arch/x86/lib/insn-eval.c index 6730c9ba02c5..6537b613d0b3 100644 --- a/arch/x86/lib/insn-eval.c +++ b/arch/x86/lib/insn-eval.c @@ -812,12 +812,25 @@ static void __user *get_addr_ref_32(struct insn *insn, struct pt_regs *regs) return (void __user *)-1L; } -/* - * return the address being referenced be instruction - * for rm=3 returning the content of the rm reg - * for rm!=3 calculates the address using SIB and Disp +/** + * get_addr_ref_64() - Obtain a 64-bit linear address + * @insn: Instruction struct with ModRM and SIB bytes and displacement + * @regs: Structure with register values as seen when entering kernel mode + * + * This function is to be used with 64-bit address encodings to obtain the + * linear memory address referred by the instruction's ModRM, SIB, + * displacement bytes and segment base address, as applicable. + * + * Return: linear address referenced by instruction and registers on success. + * -1L on error. */ -void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs) +#ifndef CONFIG_X86_64 +static void __user *get_addr_ref_64(struct insn *insn, struct pt_regs *regs) +{ + return (void __user *)-1L; +} +#else +static void __user *get_addr_ref_64(struct insn *insn, struct pt_regs *regs) { int addr_offset, base_offset, indx_offset; unsigned long linear_addr, seg_base_addr; @@ -828,6 +841,9 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs) insn_get_sib(insn); sib = insn->sib.value; + if (insn->addr_bytes != 8) + goto out_err; + if (X86_MODRM_MOD(insn->modrm.value) == 3) { addr_offset = get_reg_offset(insn, regs, REG_TYPE_RM); if (addr_offset < 0) @@ -900,5 +916,30 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs) return (void __user *)linear_addr; out_err: - return (void __user *)-1; + return (void __user *)-1L; +} +#endif /* CONFIG_X86_64 */ + +/** + * insn_get_addr_ref() - Obtain the linear address referred by instruction + * @insn: Instruction structure containing ModRM byte and displacement + * @regs: Structure with register values as seen when entering kernel mode + * + * Obtain the linear address referred by the instruction's ModRM, SIB and + * displacement bytes, and segment base, as applicable. In protected mode, + * segment limits are enforced. + * + * Return: linear address referenced by instruction and registers on success. + * -1L on error. + */ +void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs) +{ + switch (insn->addr_bytes) { + case 4: + return get_addr_ref_32(insn, regs); + case 8: + return get_addr_ref_64(insn, regs); + default: + return (void __user *)-1L; + } } -- 2.13.0