Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933578AbdCHAhh (ORCPT ); Tue, 7 Mar 2017 19:37:37 -0500 Received: from mga11.intel.com ([192.55.52.93]:39837 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933268AbdCHAhd (ORCPT ); Tue, 7 Mar 2017 19:37:33 -0500 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.36,261,1486454400"; d="scan'208";a="1105982562" 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 , Alexandre Julliard , Stas Sergeev , Fenghua Yu , "Ravi V. Shankar" , Shuah Khan , linux-kernel@vger.kernel.org, x86@kernel.org, linux-msdos@vger.kernel.org, wine-devel@winehq.org, Ricardo Neri , Adam Buchbinder , Colin Ian King , Lorenzo Stoakes , Qiaowei Ren , Nathan Howard , Adan Hawthorn , Joe Perches Subject: [v6 PATCH 03/21] x86/mpx: Do not use R/EBP as base in the SIB byte with Mod = 0 Date: Tue, 7 Mar 2017 16:32:36 -0800 Message-Id: <20170308003254.27833-4-ricardo.neri-calderon@linux.intel.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20170308003254.27833-1-ricardo.neri-calderon@linux.intel.com> References: <20170308003254.27833-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: 3369 Lines: 87 Section 2.2.1.2 of the Intel 64 and IA-32 Architectures Software Developer's Manual volume 2A states that when a SIB byte is used and the base of the SIB byte points to R/EBP (i.e., base = 5) and the mod part of the ModRM byte is zero, the value of such register will not be used as part of the address computation. To signal this, a -EDOM error is returned to indicate callers that they should ignore the value. Also, for this particular case, a displacement of 32-bits should follow the SIB byte if the mod part of ModRM is equal to zero. The instruction decoder ensures that this is the case. Cc: Dave Hansen Cc: Adam Buchbinder Cc: Colin Ian King Cc: Lorenzo Stoakes Cc: Qiaowei Ren Cc: Peter Zijlstra Cc: Nathan Howard Cc: Adan Hawthorn Cc: Joe Perches Cc: Ravi V. Shankar Cc: x86@kernel.org Signed-off-by: Ricardo Neri --- arch/x86/mm/mpx.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c index d9e92d6..ef7eb67 100644 --- a/arch/x86/mm/mpx.c +++ b/arch/x86/mm/mpx.c @@ -121,6 +121,17 @@ static int get_reg_offset(struct insn *insn, struct pt_regs *regs, case REG_TYPE_BASE: regno = X86_SIB_BASE(insn->sib.value); + /* + * If mod is 0 and register R/EBP (regno=5) is indicated in the + * base part of the SIB byte, the value of such register should + * not be used in the address computation. Also, a 32-bit + * displacement is expected in this case; the instruction + * decoder takes care of it. This is true for both R13 and + * R/EBP as REX.B will not be decoded. + */ + if (regno == 5 && X86_MODRM_MOD(insn->modrm.value) == 0) + return -EDOM; + if (X86_REX_B(insn->rex_prefix.value)) regno += 8; break; @@ -161,16 +172,21 @@ static void __user *mpx_get_addr_ref(struct insn *insn, struct pt_regs *regs) eff_addr = regs_get_register(regs, addr_offset); } else { if (insn->sib.nbytes) { + /* + * Negative values in the base and index offset means + * an error when decoding the SIB byte. Except -EDOM, + * which means that the registers should not be used + * in the address computation. + */ base_offset = get_reg_offset(insn, regs, REG_TYPE_BASE); - if (base_offset < 0) + if (unlikely(base_offset == -EDOM)) + base = 0; + else if (unlikely(base_offset < 0)) goto out_err; + else + base = regs_get_register(regs, base_offset); indx_offset = get_reg_offset(insn, regs, REG_TYPE_INDEX); - /* - * A negative offset generally means a error, except - * -EDOM, which means that the contents of the register - * should not be used as index. - */ if (unlikely(indx_offset == -EDOM)) indx = 0; else if (unlikely(indx_offset < 0)) @@ -178,7 +194,6 @@ static void __user *mpx_get_addr_ref(struct insn *insn, struct pt_regs *regs) else indx = regs_get_register(regs, indx_offset); - base = regs_get_register(regs, base_offset); eff_addr = base + indx * (1 << X86_SIB_SCALE(sib)); } else { addr_offset = get_reg_offset(insn, regs, REG_TYPE_RM); -- 2.9.3