Re: [v6 PATCH 04/21] x86/mpx, x86/insn: Relocate insn util functions to a new insn-kernel
On Wed, 2017-04-12 at 12:03 +0200, Borislav Petkov wrote: > > + * 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; > > + > > + default: > > + pr_err("invalid register type"); > > + BUG(); > > WARNING: Avoid crashing the kernel - try using WARN_ON & recovery code > rather than BUG() or BUG_ON() > #211: FILE: arch/x86/lib/insn-eval.c:90: > + BUG(); > > And checkpatch is kinda right. We need to warn here, not explode. Oh > and > that function returns negative values on error... > > Please change that with a patch ontop of the move. Sure, I will change it. -- To unsubscribe from this list: send the line "unsubscribe linux-msdos" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [v6 PATCH 03/21] x86/mpx: Do not use R/EBP as base in the SIB byte with Mod = 0
On Wed, 2017-04-12 at 00:08 +0200, Borislav Petkov wrote: > On Tue, Mar 07, 2017 at 04:32:36PM -0800, Ricardo Neri wrote: > > 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: x...@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, > > you can simply say here: "if SIB.base == 5, the base of the > register-indirect addressing is 0." This is better wording. I will change it. > > > the value of such register should > > +* not be used in the address computation. Also, a 32-bit > > Not "Also" but "In this case, a 32-bit displacement..." Will change. > > > +* 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. > > You don't need that sentence as the only thing that matters is ModRM.mod > being 0. For the specific case of ModRM.mod being 0, I feel I need to clarify that REX.B is not decoded and if SIB.base is %r13 the base is also 0. This comment adds clarity because REX.X is decoded when determining SIB.index. > > > +*/ > > + if (regno == 5 && X86_MODRM_MOD(insn->modrm.value) == 0) > > The 0 test we normally do with the ! (also flip parts of if-condition): > > if (!X86_MODRM_MOD(insn->modrm.value) && regno == 5) Will change it. > > > + 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)) > > Bah, unlikely's in something which is not really a hot path. They only > encumber readability, no need for them. I will remove them. Thanks and BR, Ricardo -- To unsubscribe from this list: send the line "unsubscribe linux-msdos" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [v6 PATCH 01/21] x86/mpx: Use signed variables to compute effective addresses
On Tue, 2017-04-11 at 23:56 +0200, Borislav Petkov wrote: > On Tue, Mar 07, 2017 at 04:32:34PM -0800, Ricardo Neri wrote: > > Even though memory addresses are unsigned. The operands used to compute the > > ... unsigned, the operands ... Oops! I will correct. -- To unsubscribe from this list: send the line "unsubscribe linux-msdos" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [v6 PATCH 12/21] x86/insn: Support both signed 32-bit and 64-bit effective addresses
On Tue, Mar 07, 2017 at 04:32:45PM -0800, Ricardo Neri wrote: > The 32-bit and 64-bit address encodings are identical. This means that we > can use the same function in both cases. In order to reuse the function for > 32-bit address encodings, we must sign-extend our 32-bit signed operands to > 64-bit signed variables (only for 64-bit builds). To decide on whether sign > extension is needed, we rely on the address size as given by the > instruction structure. > > Lastly, before computing the linear address, we must truncate our signed > 64-bit signed effective address if the address size is 32-bit. > > 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: x...@kernel.org > Signed-off-by: Ricardo Neri > --- > arch/x86/lib/insn-eval.c | 44 > 1 file changed, 32 insertions(+), 12 deletions(-) > > diff --git a/arch/x86/lib/insn-eval.c b/arch/x86/lib/insn-eval.c > index edb360f..a9a1704 100644 > --- a/arch/x86/lib/insn-eval.c > +++ b/arch/x86/lib/insn-eval.c > @@ -559,6 +559,15 @@ int insn_get_reg_offset_sib_index(struct insn *insn, > struct pt_regs *regs) > return get_reg_offset(insn, regs, REG_TYPE_INDEX); > } > > +static inline long __to_signed_long(unsigned long val, int long_bytes) > +{ > +#ifdef CONFIG_X86_64 > + return long_bytes == 4 ? (long)((int)((val) & 0x)) : (long)val; I don't think this always works as expected: --- typedef unsigned int u32; typedef unsigned long u64; int main() { u64 v = 0x1; printf("v: %ld, 0x%lx, %ld\n", v, v, (long)((int)((v) & 0x))); return 0; } -- ... v: 8589934591, 0x1, -1 Now, this should not happen on 32-bit because unsigned long is 32-bit there but can that happen on 64-bit? > +#else > + return (long)val; > +#endif > +} > + > /* > * return the address being referenced be instruction > * for rm=3 returning the content of the rm reg > @@ -567,19 +576,21 @@ int insn_get_reg_offset_sib_index(struct insn *insn, > struct pt_regs *regs) > void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs) > { > unsigned long linear_addr, seg_base_addr; > - long eff_addr, base, indx; > - int addr_offset, base_offset, indx_offset; > + long eff_addr, base, indx, tmp; > + int addr_offset, base_offset, indx_offset, addr_bytes; > insn_byte_t sib; > > insn_get_modrm(insn); > insn_get_sib(insn); > sib = insn->sib.value; > + addr_bytes = insn->addr_bytes; > > if (X86_MODRM_MOD(insn->modrm.value) == 3) { > addr_offset = get_reg_offset(insn, regs, REG_TYPE_RM); > if (addr_offset < 0) > goto out_err; > - eff_addr = regs_get_register(regs, addr_offset); > + tmp = regs_get_register(regs, addr_offset); > + eff_addr = __to_signed_long(tmp, addr_bytes); This repeats throughout the function so it begs to be a separate: get_mem_addr() or so. > seg_base_addr = insn_get_seg_base(regs, insn, addr_offset, > false); > } else { > @@ -591,20 +602,24 @@ void __user *insn_get_addr_ref(struct insn *insn, > struct pt_regs *regs) >* in the address computation. >*/ > base_offset = get_reg_offset(insn, regs, REG_TYPE_BASE); > - if (unlikely(base_offset == -EDOM)) > + if (unlikely(base_offset == -EDOM)) { > base = 0; > - else if (unlikely(base_offset < 0)) > + } else if (unlikely(base_offset < 0)) { > goto out_err; > - else > - base = regs_get_register(regs, base_offset); > + } else { > + tmp = regs_get_register(regs, base_offset); > + base = __to_signed_long(tmp, addr_bytes); > + } > > indx_offset = get_reg_offset(insn, regs, > REG_TYPE_INDEX); > - if (unlikely(indx_offset == -EDOM)) > + if (unlikely(indx_offset == -EDOM)) { > indx = 0; > - else if (unlikely(indx_offset < 0)) > +