From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Jan Beulich" Subject: [PATCH 2/5] x86emul: limit-check branch targets Date: Wed, 17 Feb 2016 09:35:57 -0700 Message-ID: <56C4AF7D02000078000D3490@prv-mh.provo.novell.com> References: <56C4AC2802000078000D3473@prv-mh.provo.novell.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=__Part2611B97D.2__=" Return-path: Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1aW559-0005Yk-Dj for xen-devel@lists.xenproject.org; Wed, 17 Feb 2016 16:36:03 +0000 In-Reply-To: <56C4AC2802000078000D3473@prv-mh.provo.novell.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: xen-devel Cc: George Dunlap , Andrew Cooper , Keir Fraser , Tim Deegan List-Id: xen-devel@lists.xenproject.org This is a MIME message. If you are reading this text, you may want to consider changing to a mail reader or gateway that understands how to properly handle MIME multipart messages. --=__Part2611B97D.2__= Content-Type: text/plain; charset=UTF-8 Content-Length: 19962 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline All branches need to #GP when their target violates the segment limit (in 16- and 32-bit modes) or is non-canonical (in 64-bit mode). For near branches facilitate this via a zero-byte instruction fetch from the target address (resulting in address translation and validation without an actual read from memory), while far branches get dealt with by breaking up the segment register loading into a read-and-validate part and a write one. The latter at once allows correcting some ordering issues in how the individual emulation steps get carried out: Before updating machine state, all exceptions unrelated to that state updating should have got raised (i.e. the only ones possibly resulting in partly updated state are faulting memory writes [pushes]). Note that while not immediately needed here, write and distinct read emulation routines get updated to deal with zero byte accesses too, for overall consistency. Reported-by: =C3=A5=CB=86=CB=9C=C3=A4=C2=BB=C2=A4 Signed-off-by: Jan Beulich --- a/tools/tests/x86_emulator/x86_emulate.c +++ b/tools/tests/x86_emulator/x86_emulate.c @@ -8,6 +8,8 @@ typedef bool bool_t; +#define is_canonical_address(x) (((int64_t)(x) >> 47) =3D=3D ((int64_t)(x) >> 63)) + #define BUG() abort() #define ASSERT assert --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -745,7 +745,7 @@ static int __hvmemul_read( rc =3D hvmemul_virtual_to_linear( seg, offset, bytes, &reps, access_type, hvmemul_ctxt, &addr); - if ( rc !=3D X86EMUL_OKAY ) + if ( rc !=3D X86EMUL_OKAY || !bytes ) return rc; if ( ((access_type !=3D hvm_access_insn_fetch =3F vio->mmio_access.read_access @@ -811,13 +811,17 @@ static int hvmemul_insn_fetch( container_of(ctxt, struct hvm_emulate_ctxt, ctxt); unsigned int insn_off =3D offset - hvmemul_ctxt->insn_buf_eip; - /* Fall back if requested bytes are not in the prefetch cache. */ - if ( unlikely((insn_off + bytes) > hvmemul_ctxt->insn_buf_bytes) ) + /* + * Fall back if requested bytes are not in the prefetch cache. + * But always perform the (fake) read when bytes =3D=3D 0. + */ + if ( !bytes || + unlikely((insn_off + bytes) > hvmemul_ctxt->insn_buf_bytes) ) { int rc =3D __hvmemul_read(seg, offset, p_data, bytes, hvm_access_insn_fetch, hvmemul_ctxt); - if ( rc =3D=3D X86EMUL_OKAY ) + if ( rc =3D=3D X86EMUL_OKAY && bytes ) { ASSERT(insn_off + bytes <=3D sizeof(hvmemul_ctxt->insn_buf)); memcpy(&hvmemul_ctxt->insn_buf[insn_off], p_data, bytes); @@ -849,7 +853,7 @@ static int hvmemul_write( rc =3D hvmemul_virtual_to_linear( seg, offset, bytes, &reps, hvm_access_write, hvmemul_ctxt, &addr); - if ( rc !=3D X86EMUL_OKAY ) + if ( rc !=3D X86EMUL_OKAY || !bytes ) return rc; if ( vio->mmio_access.write_access && --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -3685,7 +3685,7 @@ int hvm_virtual_to_linear_addr( * Certain of them are not done in native real mode anyway. */ addr =3D (uint32_t)(addr + reg->base); - last_byte =3D (uint32_t)addr + bytes - 1; + last_byte =3D (uint32_t)addr + bytes - !!bytes; if ( last_byte < addr ) return 0; } @@ -3709,7 +3709,7 @@ int hvm_virtual_to_linear_addr( break; } - last_byte =3D (uint32_t)offset + bytes - 1; + last_byte =3D (uint32_t)offset + bytes - !!bytes; /* Is this a grows-down data segment=3F Special limit check if so. */ if ( (reg->attr.fields.type & 0xc) =3D=3D 0x4 ) @@ -3740,7 +3740,7 @@ int hvm_virtual_to_linear_addr( if ( (seg =3D=3D x86_seg_fs) || (seg =3D=3D x86_seg_gs) ) addr +=3D reg->base; - last_byte =3D addr + bytes - 1; + last_byte =3D addr + bytes - !!bytes; if ( !is_canonical_address(addr) || last_byte < addr || !is_canonical_address(last_byte) ) return 0; --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -157,7 +157,7 @@ hvm_read(enum x86_segment seg, rc =3D hvm_translate_linear_addr( seg, offset, bytes, access_type, sh_ctxt, &addr); - if ( rc ) + if ( rc || !bytes ) return rc; if ( access_type =3D=3D hvm_access_insn_fetch ) @@ -241,7 +241,7 @@ hvm_emulate_write(enum x86_segment seg, rc =3D hvm_translate_linear_addr( seg, offset, bytes, hvm_access_write, sh_ctxt, &addr); - if ( rc ) + if ( rc || !bytes ) return rc; return v->arch.paging.mode->shadow.x86_emulate_write( --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -5126,10 +5126,11 @@ static int ptwr_emulated_read( unsigned int bytes, struct x86_emulate_ctxt *ctxt) { - unsigned int rc; + unsigned int rc =3D bytes; unsigned long addr =3D offset; - if ( (rc =3D copy_from_user(p_data, (void *)addr, bytes)) !=3D 0 ) + if ( !__addr_ok(addr) || + (rc =3D __copy_from_user(p_data, (void *)addr, bytes)) ) { propagate_page_fault(addr + bytes - rc, 0); /* read fault */ return X86EMUL_EXCEPTION; @@ -5278,7 +5279,7 @@ static int ptwr_emulated_write( { paddr_t val =3D 0; - if ( (bytes > sizeof(paddr_t)) || (bytes & (bytes -1)) ) + if ( (bytes > sizeof(paddr_t)) || (bytes & (bytes - 1)) || !bytes ) { MEM_LOG("ptwr_emulate: bad write size (addr=3D%lx, bytes=3D%u)", offset, bytes); @@ -5394,7 +5395,8 @@ int mmio_ro_emulated_write( struct mmio_ro_emulate_ctxt *mmio_ro_ctxt =3D ctxt->data; /* Only allow naturally-aligned stores at the original %cr2 address. */ - if ( ((bytes | offset) & (bytes - 1)) || offset !=3D mmio_ro_ctxt->cr2 ) + if ( ((bytes | offset) & (bytes - 1)) || !bytes || + offset !=3D mmio_ro_ctxt->cr2 ) { MEM_LOG("mmio_ro_emulate: bad access (cr2=3D%lx, addr=3D%lx, bytes=3D%u)", mmio_ro_ctxt->cr2, offset, bytes); @@ -5423,7 +5425,7 @@ int mmcfg_intercept_write( * Only allow naturally-aligned stores no wider than 4 bytes to the * original %cr2 address. */ - if ( ((bytes | offset) & (bytes - 1)) || bytes > 4 || + if ( ((bytes | offset) & (bytes - 1)) || bytes > 4 || !bytes || offset !=3D mmio_ctxt->cr2 ) { MEM_LOG("mmcfg_intercept: bad write (cr2=3D%lx, addr=3D%lx, bytes=3D%u)", --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -642,14 +642,26 @@ do { #define jmp_rel(rel) \ do { \ - int _rel =3D (int)(rel); \ - _regs.eip +=3D _rel; \ + unsigned long ip =3D _regs.eip + (int)(rel); \ if ( op_bytes =3D=3D 2 ) \ - _regs.eip =3D (uint16_t)_regs.eip; \ + ip =3D (uint16_t)ip; \ else if ( !mode_64bit() ) \ - _regs.eip =3D (uint32_t)_regs.eip; \ + ip =3D (uint32_t)ip; \ + rc =3D ops->insn_fetch(x86_seg_cs, ip, NULL, 0, ctxt); \ + if ( rc ) goto done; \ + _regs.eip =3D ip; \ } while (0) +#define validate_far_branch(cs, ip) \ + generate_exception_if(in_longmode(ctxt, ops) && (cs)->attr.fields.l \ + =3F !is_canonical_address(ip) \ + : (ip) > (cs)->limit, EXC_GP, 0) + +#define commit_far_branch(cs, ip) ({ \ + validate_far_branch(cs, ip); \ + ops->write_segment(x86_seg_cs, cs, ctxt); \ +}) + struct fpu_insn_ctxt { uint8_t insn_bytes; uint8_t exn_raised; @@ -1099,29 +1111,30 @@ static int realmode_load_seg( enum x86_segment seg, uint16_t sel, + struct segment_register *sreg, struct x86_emulate_ctxt *ctxt, const struct x86_emulate_ops *ops) { - struct segment_register reg; - int rc; + int rc =3D ops->read_segment(seg, sreg, ctxt); - if ( (rc =3D ops->read_segment(seg, ®, ctxt)) !=3D 0 ) - return rc; - - reg.sel =3D sel; - reg.base =3D (uint32_t)sel << 4; + if ( !rc ) + { + sreg->sel =3D sel; + sreg->base =3D (uint32_t)sel << 4; + } - return ops->write_segment(seg, ®, ctxt); + return rc; } static int protmode_load_seg( enum x86_segment seg, uint16_t sel, bool_t is_ret, + struct segment_register *sreg, struct x86_emulate_ctxt *ctxt, const struct x86_emulate_ops *ops) { - struct segment_register desctab, ss, segr; + struct segment_register desctab, ss; struct { uint32_t a, b; } desc; uint8_t dpl, rpl, cpl; uint32_t new_desc_b, a_flag =3D 0x100; @@ -1132,8 +1145,8 @@ protmode_load_seg( { if ( (seg =3D=3D x86_seg_cs) || (seg =3D=3D x86_seg_ss) ) goto raise_exn; - memset(&segr, 0, sizeof(segr)); - return ops->write_segment(seg, &segr, ctxt); + memset(sreg, 0, sizeof(*sreg)); + return X86EMUL_OKAY; } /* System segment descriptors must reside in the GDT. */ @@ -1242,16 +1255,16 @@ protmode_load_seg( desc.b |=3D a_flag; skip_accessed_flag: - segr.base =3D (((desc.b << 0) & 0xff000000u) | - ((desc.b << 16) & 0x00ff0000u) | - ((desc.a >> 16) & 0x0000ffffu)); - segr.attr.bytes =3D (((desc.b >> 8) & 0x00ffu) | - ((desc.b >> 12) & 0x0f00u)); - segr.limit =3D (desc.b & 0x000f0000u) | (desc.a & 0x0000ffffu); - if ( segr.attr.fields.g ) - segr.limit =3D (segr.limit << 12) | 0xfffu; - segr.sel =3D sel; - return ops->write_segment(seg, &segr, ctxt); + sreg->base =3D (((desc.b << 0) & 0xff000000u) | + ((desc.b << 16) & 0x00ff0000u) | + ((desc.a >> 16) & 0x0000ffffu)); + sreg->attr.bytes =3D (((desc.b >> 8) & 0x00ffu) | + ((desc.b >> 12) & 0x0f00u)); + sreg->limit =3D (desc.b & 0x000f0000u) | (desc.a & 0x0000ffffu); + if ( sreg->attr.fields.g ) + sreg->limit =3D (sreg->limit << 12) | 0xfffu; + sreg->sel =3D sel; + return X86EMUL_OKAY; raise_exn: if ( ops->inject_hw_exception =3D=3D NULL ) @@ -1265,17 +1278,29 @@ static int load_seg( enum x86_segment seg, uint16_t sel, bool_t is_ret, + struct segment_register *sreg, struct x86_emulate_ctxt *ctxt, const struct x86_emulate_ops *ops) { + struct segment_register reg; + int rc; + if ( (ops->read_segment =3D=3D NULL) || (ops->write_segment =3D=3D NULL) ) return X86EMUL_UNHANDLEABLE; + if ( !sreg ) + sreg =3D ® + if ( in_protmode(ctxt, ops) ) - return protmode_load_seg(seg, sel, is_ret, ctxt, ops); + rc =3D protmode_load_seg(seg, sel, is_ret, sreg, ctxt, ops); + else + rc =3D realmode_load_seg(seg, sel, sreg, ctxt, ops); + + if ( !rc && sreg =3D=3D ® ) + rc =3D ops->write_segment(seg, sreg, ctxt); - return realmode_load_seg(seg, sel, ctxt, ops); + return rc; } void * @@ -1970,6 +1995,8 @@ x86_emulate( switch ( b ) { + struct segment_register cs; + case 0x00 ... 0x05: add: /* add */ emulate_2op_SrcV("add", src, dst, _regs.eflags); break; @@ -2031,7 +2058,7 @@ x86_emulate( if ( (rc =3D read_ulong(x86_seg_ss, sp_post_inc(op_bytes), &dst.val, op_bytes, ctxt, ops)) !=3D 0 ) goto done; - if ( (rc =3D load_seg(src.val, dst.val, 0, ctxt, ops)) !=3D 0 ) + if ( (rc =3D load_seg(src.val, dst.val, 0, NULL, ctxt, ops)) !=3D 0 ) return rc; break; @@ -2364,7 +2391,7 @@ x86_emulate( enum x86_segment seg =3D decode_segment(modrm_reg); generate_exception_if(seg =3D=3D decode_segment_failed, EXC_UD, -1); generate_exception_if(seg =3D=3D x86_seg_cs, EXC_UD, -1); - if ( (rc =3D load_seg(seg, src.val, 0, ctxt, ops)) !=3D 0 ) + if ( (rc =3D load_seg(seg, src.val, 0, NULL, ctxt, ops)) !=3D 0 ) goto done; if ( seg =3D=3D x86_seg_ss ) ctxt->retire.flags.mov_ss =3D 1; @@ -2439,14 +2466,15 @@ x86_emulate( sel =3D insn_fetch_type(uint16_t); if ( (rc =3D ops->read_segment(x86_seg_cs, ®, ctxt)) || - (rc =3D ops->write(x86_seg_ss, sp_pre_dec(op_bytes), + (rc =3D load_seg(x86_seg_cs, sel, 0, &cs, ctxt, ops)) || + (validate_far_branch(&cs, eip), + rc =3D ops->write(x86_seg_ss, sp_pre_dec(op_bytes), ®.sel, op_bytes, ctxt)) || (rc =3D ops->write(x86_seg_ss, sp_pre_dec(op_bytes), - &_regs.eip, op_bytes, ctxt)) ) + &_regs.eip, op_bytes, ctxt)) || + (rc =3D ops->write_segment(x86_seg_cs, &cs, ctxt)) ) goto done; - if ( (rc =3D load_seg(x86_seg_cs, sel, 0, ctxt, ops)) !=3D 0 ) - goto done; _regs.eip =3D eip; break; } @@ -2664,7 +2692,8 @@ x86_emulate( int offset =3D (b =3D=3D 0xc2) =3F insn_fetch_type(uint16_t) : 0; op_bytes =3D ((op_bytes =3D=3D 4) && mode_64bit()) =3F 8 : op_bytes; if ( (rc =3D read_ulong(x86_seg_ss, sp_post_inc(op_bytes + offset), - &dst.val, op_bytes, ctxt, ops)) !=3D 0 ) + &dst.val, op_bytes, ctxt, ops)) !=3D 0 || + (rc =3D ops->insn_fetch(x86_seg_cs, dst.val, NULL, 0, ctxt)) ) goto done; _regs.eip =3D dst.val; break; @@ -2679,7 +2708,7 @@ x86_emulate( if ( (rc =3D read_ulong(src.mem.seg, src.mem.off + src.bytes, &sel, 2, ctxt, ops)) !=3D 0 ) goto done; - if ( (rc =3D load_seg(dst.val, sel, 0, ctxt, ops)) !=3D 0 ) + if ( (rc =3D load_seg(dst.val, sel, 0, NULL, ctxt, ops)) !=3D 0 ) goto done; dst.val =3D src.val; break; @@ -2753,7 +2782,8 @@ x86_emulate( &dst.val, op_bytes, ctxt, ops)) || (rc =3D read_ulong(x86_seg_ss, sp_post_inc(op_bytes + offset), &src.val, op_bytes, ctxt, ops)) || - (rc =3D load_seg(x86_seg_cs, src.val, 1, ctxt, ops)) ) + (rc =3D load_seg(x86_seg_cs, src.val, 1, &cs, ctxt, ops)) || + (rc =3D commit_far_branch(&cs, dst.val)) ) goto done; _regs.eip =3D dst.val; break; @@ -2782,7 +2812,7 @@ x86_emulate( goto swint; case 0xcf: /* iret */ { - unsigned long cs, eip, eflags; + unsigned long sel, eip, eflags; uint32_t mask =3D EFLG_VIP | EFLG_VIF | EFLG_VM; if ( !mode_ring0() ) mask |=3D EFLG_IOPL; @@ -2792,7 +2822,7 @@ x86_emulate( if ( (rc =3D read_ulong(x86_seg_ss, sp_post_inc(op_bytes), &eip, op_bytes, ctxt, ops)) || (rc =3D read_ulong(x86_seg_ss, sp_post_inc(op_bytes), - &cs, op_bytes, ctxt, ops)) || + &sel, op_bytes, ctxt, ops)) || (rc =3D read_ulong(x86_seg_ss, sp_post_inc(op_bytes), &eflags, op_bytes, ctxt, ops)) ) goto done; @@ -2802,7 +2832,8 @@ x86_emulate( _regs.eflags &=3D mask; _regs.eflags |=3D (uint32_t)(eflags & ~mask) | 0x02; _regs.eip =3D eip; - if ( (rc =3D load_seg(x86_seg_cs, cs, 1, ctxt, ops)) !=3D 0 ) + if ( (rc =3D load_seg(x86_seg_cs, sel, 1, &cs, ctxt, ops)) || + (rc =3D commit_far_branch(&cs, eip)) ) goto done; break; } @@ -3432,7 +3463,8 @@ x86_emulate( generate_exception_if(mode_64bit(), EXC_UD, -1); eip =3D insn_fetch_bytes(op_bytes); sel =3D insn_fetch_type(uint16_t); - if ( (rc =3D load_seg(x86_seg_cs, sel, 0, ctxt, ops)) !=3D 0 ) + if ( (rc =3D load_seg(x86_seg_cs, sel, 0, &cs, ctxt, ops)) || + (rc =3D commit_far_branch(&cs, eip)) ) goto done; _regs.eip =3D eip; break; @@ -3702,10 +3734,14 @@ x86_emulate( break; case 2: /* call (near) */ dst.val =3D _regs.eip; + if ( (rc =3D ops->insn_fetch(x86_seg_cs, src.val, NULL, 0, ctxt)) ) + goto done; _regs.eip =3D src.val; src.val =3D dst.val; goto push; case 4: /* jmp (near) */ + if ( (rc =3D ops->insn_fetch(x86_seg_cs, src.val, NULL, 0, ctxt)) ) + goto done; _regs.eip =3D src.val; dst.type =3D OP_NONE; break; @@ -3724,14 +3760,17 @@ x86_emulate( struct segment_register reg; fail_if(ops->read_segment =3D=3D NULL); if ( (rc =3D ops->read_segment(x86_seg_cs, ®, ctxt)) || - (rc =3D ops->write(x86_seg_ss, sp_pre_dec(op_bytes), + (rc =3D load_seg(x86_seg_cs, sel, 0, &cs, ctxt, ops)) || + (validate_far_branch(&cs, src.val), + rc =3D ops->write(x86_seg_ss, sp_pre_dec(op_bytes), ®.sel, op_bytes, ctxt)) || (rc =3D ops->write(x86_seg_ss, sp_pre_dec(op_bytes), - &_regs.eip, op_bytes, ctxt)) ) + &_regs.eip, op_bytes, ctxt)) || + (rc =3D ops->write_segment(x86_seg_cs, &cs, ctxt)) ) goto done; } - - if ( (rc =3D load_seg(x86_seg_cs, sel, 0, ctxt, ops)) !=3D 0 ) + else if ( (rc =3D load_seg(x86_seg_cs, sel, 0, &cs, ctxt, ops)) || + (rc =3D commit_far_branch(&cs, src.val)) ) goto done; _regs.eip =3D src.val; @@ -3816,7 +3855,7 @@ x86_emulate( generate_exception_if(!in_protmode(ctxt, ops), EXC_UD, -1); generate_exception_if(!mode_ring0(), EXC_GP, 0); if ( (rc =3D load_seg((modrm_reg & 1) =3F x86_seg_tr : x86_seg_ldtr, - src.val, 0, ctxt, ops)) !=3D 0 ) + src.val, 0, NULL, ctxt, ops)) !=3D 0 ) goto done; break; @@ -4269,6 +4308,9 @@ x86_emulate( goto done; generate_exception_if(!(msr_content & 0xfffc), EXC_GP, 0); + generate_exception_if(user64 && (!is_canonical_address(_regs.edx) || + !is_canonical_address(_regs.ecx)), + EXC_GP, 0); cs.sel =3D (msr_content | 3) + /* SELECTOR_RPL_MASK */ (user64 =3F 32 : 16); --=__Part2611B97D.2__= Content-Type: text/plain; name="x86emul-branch-limit-checks.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="x86emul-branch-limit-checks.patch" x86emul: limit-check branch targets=0A=0AAll branches need to #GP when = their target violates the segment limit=0A(in 16- and 32-bit modes) or is = non-canonical (in 64-bit mode). For=0Anear branches facilitate this via a = zero-byte instruction fetch from=0Athe target address (resulting in = address translation and validation=0Awithout an actual read from memory), = while far branches get dealt with=0Aby breaking up the segment register = loading into a read-and-validate=0Apart and a write one. The latter at = once allows correcting some=0Aordering issues in how the individual = emulation steps get carried out:=0ABefore updating machine state, all = exceptions unrelated to that state=0Aupdating should have got raised (i.e. = the only ones possibly resulting=0Ain partly updated state are faulting = memory writes [pushes]).=0A=0ANote that while not immediately needed here, = write and distinct read=0Aemulation routines get updated to deal with zero = byte accesses too, for=0Aoverall consistency.=0A=0AReported-by: = =E5=88=98=E4=BB=A4 =0ASigned-off-by: Jan Beulich = =0A=0A--- a/tools/tests/x86_emulator/x86_emulate.c=0A+++= b/tools/tests/x86_emulator/x86_emulate.c=0A@@ -8,6 +8,8 @@=0A =0A typedef = bool bool_t;=0A =0A+#define is_canonical_address(x) (((int64_t)(x) >> 47) = =3D=3D ((int64_t)(x) >> 63))=0A+=0A #define BUG() abort()=0A #define = ASSERT assert=0A =0A--- a/xen/arch/x86/hvm/emulate.c=0A+++ b/xen/arch/x86/h= vm/emulate.c=0A@@ -745,7 +745,7 @@ static int __hvmemul_read(=0A =0A = rc =3D hvmemul_virtual_to_linear(=0A seg, offset, bytes, &reps, = access_type, hvmemul_ctxt, &addr);=0A- if ( rc !=3D X86EMUL_OKAY )=0A+ = if ( rc !=3D X86EMUL_OKAY || !bytes )=0A return rc;=0A if ( = ((access_type !=3D hvm_access_insn_fetch=0A ? vio->mmio_access.r= ead_access=0A@@ -811,13 +811,17 @@ static int hvmemul_insn_fetch(=0A = container_of(ctxt, struct hvm_emulate_ctxt, ctxt);=0A unsigned int = insn_off =3D offset - hvmemul_ctxt->insn_buf_eip;=0A =0A- /* Fall back = if requested bytes are not in the prefetch cache. */=0A- if ( unlikely((= insn_off + bytes) > hvmemul_ctxt->insn_buf_bytes) )=0A+ /*=0A+ * = Fall back if requested bytes are not in the prefetch cache.=0A+ * But = always perform the (fake) read when bytes =3D=3D 0.=0A+ */=0A+ if ( = !bytes ||=0A+ unlikely((insn_off + bytes) > hvmemul_ctxt->insn_buf_= bytes) )=0A {=0A int rc =3D __hvmemul_read(seg, offset, = p_data, bytes,=0A hvm_access_insn_fetch, = hvmemul_ctxt);=0A =0A- if ( rc =3D=3D X86EMUL_OKAY )=0A+ if = ( rc =3D=3D X86EMUL_OKAY && bytes )=0A {=0A ASSERT(insn= _off + bytes <=3D sizeof(hvmemul_ctxt->insn_buf));=0A = memcpy(&hvmemul_ctxt->insn_buf[insn_off], p_data, bytes);=0A@@ -849,7 = +853,7 @@ static int hvmemul_write(=0A =0A rc =3D hvmemul_virtual_to_li= near(=0A seg, offset, bytes, &reps, hvm_access_write, hvmemul_ctxt,= &addr);=0A- if ( rc !=3D X86EMUL_OKAY )=0A+ if ( rc !=3D X86EMUL_OKA= Y || !bytes )=0A return rc;=0A =0A if ( vio->mmio_access.write_= access &&=0A--- a/xen/arch/x86/hvm/hvm.c=0A+++ b/xen/arch/x86/hvm/hvm.c=0A@= @ -3685,7 +3685,7 @@ int hvm_virtual_to_linear_addr(=0A * Certain = of them are not done in native real mode anyway.=0A */=0A = addr =3D (uint32_t)(addr + reg->base);=0A- last_byte =3D (uint32_t)a= ddr + bytes - 1;=0A+ last_byte =3D (uint32_t)addr + bytes - = !!bytes;=0A if ( last_byte < addr )=0A return 0;=0A = }=0A@@ -3709,7 +3709,7 @@ int hvm_virtual_to_linear_addr(=0A = break;=0A }=0A =0A- last_byte =3D (uint32_t)offset + bytes = - 1;=0A+ last_byte =3D (uint32_t)offset + bytes - !!bytes;=0A =0A = /* Is this a grows-down data segment? Special limit check if so. = */=0A if ( (reg->attr.fields.type & 0xc) =3D=3D 0x4 )=0A@@ -3740,7 = +3740,7 @@ int hvm_virtual_to_linear_addr(=0A if ( (seg =3D=3D = x86_seg_fs) || (seg =3D=3D x86_seg_gs) )=0A addr +=3D = reg->base;=0A =0A- last_byte =3D addr + bytes - 1;=0A+ = last_byte =3D addr + bytes - !!bytes;=0A if ( !is_canonical_address= (addr) || last_byte < addr ||=0A !is_canonical_address(last_by= te) )=0A return 0;=0A--- a/xen/arch/x86/mm/shadow/common.c=0A++= + b/xen/arch/x86/mm/shadow/common.c=0A@@ -157,7 +157,7 @@ hvm_read(enum = x86_segment seg,=0A =0A rc =3D hvm_translate_linear_addr(=0A = seg, offset, bytes, access_type, sh_ctxt, &addr);=0A- if ( rc )=0A+ = if ( rc || !bytes )=0A return rc;=0A =0A if ( access_type = =3D=3D hvm_access_insn_fetch )=0A@@ -241,7 +241,7 @@ hvm_emulate_write(enum= x86_segment seg,=0A =0A rc =3D hvm_translate_linear_addr(=0A = seg, offset, bytes, hvm_access_write, sh_ctxt, &addr);=0A- if ( rc = )=0A+ if ( rc || !bytes )=0A return rc;=0A =0A return = v->arch.paging.mode->shadow.x86_emulate_write(=0A--- a/xen/arch/x86/mm.c=0A= +++ b/xen/arch/x86/mm.c=0A@@ -5126,10 +5126,11 @@ static int ptwr_emulated_= read(=0A unsigned int bytes,=0A struct x86_emulate_ctxt *ctxt)=0A = {=0A- unsigned int rc;=0A+ unsigned int rc =3D bytes;=0A = unsigned long addr =3D offset;=0A =0A- if ( (rc =3D copy_from_user(p_dat= a, (void *)addr, bytes)) !=3D 0 )=0A+ if ( !__addr_ok(addr) ||=0A+ = (rc =3D __copy_from_user(p_data, (void *)addr, bytes)) )=0A {=0A = propagate_page_fault(addr + bytes - rc, 0); /* read fault */=0A = return X86EMUL_EXCEPTION;=0A@@ -5278,7 +5279,7 @@ static int ptwr_emulate= d_write(=0A {=0A paddr_t val =3D 0;=0A =0A- if ( (bytes > sizeof(pad= dr_t)) || (bytes & (bytes -1)) )=0A+ if ( (bytes > sizeof(paddr_t)) || = (bytes & (bytes - 1)) || !bytes )=0A {=0A MEM_LOG("ptwr_emulate= : bad write size (addr=3D%lx, bytes=3D%u)",=0A offset, = bytes);=0A@@ -5394,7 +5395,8 @@ int mmio_ro_emulated_write(=0A struct = mmio_ro_emulate_ctxt *mmio_ro_ctxt =3D ctxt->data;=0A =0A /* Only = allow naturally-aligned stores at the original %cr2 address. */=0A- if = ( ((bytes | offset) & (bytes - 1)) || offset !=3D mmio_ro_ctxt->cr2 )=0A+ = if ( ((bytes | offset) & (bytes - 1)) || !bytes ||=0A+ offset = !=3D mmio_ro_ctxt->cr2 )=0A {=0A MEM_LOG("mmio_ro_emulate: bad = access (cr2=3D%lx, addr=3D%lx, bytes=3D%u)",=0A mmio_ro_ctx= t->cr2, offset, bytes);=0A@@ -5423,7 +5425,7 @@ int mmcfg_intercept_write(= =0A * Only allow naturally-aligned stores no wider than 4 bytes to = the=0A * original %cr2 address.=0A */=0A- if ( ((bytes | = offset) & (bytes - 1)) || bytes > 4 ||=0A+ if ( ((bytes | offset) & = (bytes - 1)) || bytes > 4 || !bytes ||=0A offset !=3D mmio_ctxt->c= r2 )=0A {=0A MEM_LOG("mmcfg_intercept: bad write (cr2=3D%lx, = addr=3D%lx, bytes=3D%u)",=0A--- a/xen/arch/x86/x86_emulate/x86_emulate.c=0A= +++ b/xen/arch/x86/x86_emulate/x86_emulate.c=0A@@ -642,14 +642,26 @@ do = {=0A =0A #define jmp_rel(rel) = \=0A do { = \=0A- int _rel =3D (int)(rel); = \=0A- _regs.eip +=3D _rel; = \=0A+ unsigned long ip =3D _regs.eip + (int)(rel); = \=0A if ( op_bytes =3D=3D 2 ) = \=0A- _regs.eip =3D (uint16_t)_regs.eip; = \=0A+ ip =3D (uint16_t)ip; = \=0A else if ( !mode_64bit() ) = \=0A- _regs.eip =3D (uint32_t)_r= egs.eip; \=0A+ ip =3D (uint32_t)ip; = \=0A+ rc =3D ops->insn_fetch= (x86_seg_cs, ip, NULL, 0, ctxt); \=0A+ if ( rc ) goto = done; \=0A+ _regs.eip = =3D ip; \=0A } while = (0)=0A =0A+#define validate_far_branch(cs, ip) = \=0A+ generate_exception_if(in_longmode(ctxt, ops) && (cs)->attr= .fields.l \=0A+ ? !is_canonical_address(ip) = \=0A+ : (ip) > (cs)->limit, EXC_GP, = 0)=0A+=0A+#define commit_far_branch(cs, ip) ({ = \=0A+ validate_far_branch(cs, ip); = \=0A+ ops->write_segment(x86_seg_cs, cs, ctxt); = \=0A+})=0A+=0A struct fpu_insn_ctxt {=0A uint8_t insn_bytes;= =0A uint8_t exn_raised;=0A@@ -1099,29 +1111,30 @@ static int=0A = realmode_load_seg(=0A enum x86_segment seg,=0A uint16_t sel,=0A+ = struct segment_register *sreg,=0A struct x86_emulate_ctxt *ctxt,=0A = const struct x86_emulate_ops *ops)=0A {=0A- struct segment_register = reg;=0A- int rc;=0A+ int rc =3D ops->read_segment(seg, sreg, = ctxt);=0A =0A- if ( (rc =3D ops->read_segment(seg, ®, ctxt)) !=3D 0 = )=0A- return rc;=0A-=0A- reg.sel =3D sel;=0A- reg.base =3D = (uint32_t)sel << 4;=0A+ if ( !rc )=0A+ {=0A+ sreg->sel =3D = sel;=0A+ sreg->base =3D (uint32_t)sel << 4;=0A+ }=0A =0A- = return ops->write_segment(seg, ®, ctxt);=0A+ return rc;=0A }=0A =0A = static int=0A protmode_load_seg(=0A enum x86_segment seg,=0A = uint16_t sel, bool_t is_ret,=0A+ struct segment_register *sreg,=0A = struct x86_emulate_ctxt *ctxt,=0A const struct x86_emulate_ops = *ops)=0A {=0A- struct segment_register desctab, ss, segr;=0A+ struct = segment_register desctab, ss;=0A struct { uint32_t a, b; } desc;=0A = uint8_t dpl, rpl, cpl;=0A uint32_t new_desc_b, a_flag =3D 0x100;=0A@@ = -1132,8 +1145,8 @@ protmode_load_seg(=0A {=0A if ( (seg =3D=3D = x86_seg_cs) || (seg =3D=3D x86_seg_ss) )=0A goto raise_exn;=0A-= memset(&segr, 0, sizeof(segr));=0A- return ops->write_segmen= t(seg, &segr, ctxt);=0A+ memset(sreg, 0, sizeof(*sreg));=0A+ = return X86EMUL_OKAY;=0A }=0A =0A /* System segment descriptors = must reside in the GDT. */=0A@@ -1242,16 +1255,16 @@ protmode_load_seg(=0A = desc.b |=3D a_flag;=0A =0A skip_accessed_flag:=0A- segr.base =3D = (((desc.b << 0) & 0xff000000u) |=0A- ((desc.b << 16) & = 0x00ff0000u) |=0A- ((desc.a >> 16) & 0x0000ffffu));=0A- = segr.attr.bytes =3D (((desc.b >> 8) & 0x00ffu) |=0A- = ((desc.b >> 12) & 0x0f00u));=0A- segr.limit =3D (desc.b & 0x000f0000u) = | (desc.a & 0x0000ffffu);=0A- if ( segr.attr.fields.g )=0A- = segr.limit =3D (segr.limit << 12) | 0xfffu;=0A- segr.sel =3D sel;=0A- = return ops->write_segment(seg, &segr, ctxt);=0A+ sreg->base =3D = (((desc.b << 0) & 0xff000000u) |=0A+ ((desc.b << 16) & = 0x00ff0000u) |=0A+ ((desc.a >> 16) & 0x0000ffffu));=0A+ = sreg->attr.bytes =3D (((desc.b >> 8) & 0x00ffu) |=0A+ = ((desc.b >> 12) & 0x0f00u));=0A+ sreg->limit =3D (desc.b & = 0x000f0000u) | (desc.a & 0x0000ffffu);=0A+ if ( sreg->attr.fields.g = )=0A+ sreg->limit =3D (sreg->limit << 12) | 0xfffu;=0A+ = sreg->sel =3D sel;=0A+ return X86EMUL_OKAY;=0A =0A raise_exn:=0A = if ( ops->inject_hw_exception =3D=3D NULL )=0A@@ -1265,17 +1278,29 @@ = static int=0A load_seg(=0A enum x86_segment seg,=0A uint16_t sel, = bool_t is_ret,=0A+ struct segment_register *sreg,=0A struct = x86_emulate_ctxt *ctxt,=0A const struct x86_emulate_ops *ops)=0A {=0A+ = struct segment_register reg;=0A+ int rc;=0A+=0A if ( (ops->read_s= egment =3D=3D NULL) ||=0A (ops->write_segment =3D=3D NULL) )=0A = return X86EMUL_UNHANDLEABLE;=0A =0A+ if ( !sreg )=0A+ sreg = =3D ®=0A+=0A if ( in_protmode(ctxt, ops) )=0A- return = protmode_load_seg(seg, sel, is_ret, ctxt, ops);=0A+ rc =3D = protmode_load_seg(seg, sel, is_ret, sreg, ctxt, ops);=0A+ else=0A+ = rc =3D realmode_load_seg(seg, sel, sreg, ctxt, ops);=0A+=0A+ if ( !rc = && sreg =3D=3D ® )=0A+ rc =3D ops->write_segment(seg, sreg, = ctxt);=0A =0A- return realmode_load_seg(seg, sel, ctxt, ops);=0A+ = return rc;=0A }=0A =0A void *=0A@@ -1970,6 +1995,8 @@ x86_emulate(=0A =0A = switch ( b )=0A {=0A+ struct segment_register cs;=0A+=0A = case 0x00 ... 0x05: add: /* add */=0A emulate_2op_SrcV("add", src, = dst, _regs.eflags);=0A break;=0A@@ -2031,7 +2058,7 @@ x86_emulate(= =0A if ( (rc =3D read_ulong(x86_seg_ss, sp_post_inc(op_bytes),=0A = &dst.val, op_bytes, ctxt, ops)) !=3D 0 )=0A = goto done;=0A- if ( (rc =3D load_seg(src.val, dst.val, 0, = ctxt, ops)) !=3D 0 )=0A+ if ( (rc =3D load_seg(src.val, dst.val, 0, = NULL, ctxt, ops)) !=3D 0 )=0A return rc;=0A break;=0A = =0A@@ -2364,7 +2391,7 @@ x86_emulate(=0A enum x86_segment seg =3D = decode_segment(modrm_reg);=0A generate_exception_if(seg =3D=3D = decode_segment_failed, EXC_UD, -1);=0A generate_exception_if(seg = =3D=3D x86_seg_cs, EXC_UD, -1);=0A- if ( (rc =3D load_seg(seg, = src.val, 0, ctxt, ops)) !=3D 0 )=0A+ if ( (rc =3D load_seg(seg, = src.val, 0, NULL, ctxt, ops)) !=3D 0 )=0A goto done;=0A = if ( seg =3D=3D x86_seg_ss )=0A ctxt->retire.flags.mov_ss =3D = 1;=0A@@ -2439,14 +2466,15 @@ x86_emulate(=0A sel =3D insn_fetch_typ= e(uint16_t);=0A =0A if ( (rc =3D ops->read_segment(x86_seg_cs, = ®, ctxt)) ||=0A- (rc =3D ops->write(x86_seg_ss, sp_pre_dec(o= p_bytes),=0A+ (rc =3D load_seg(x86_seg_cs, sel, 0, &cs, ctxt, = ops)) ||=0A+ (validate_far_branch(&cs, eip),=0A+ = rc =3D ops->write(x86_seg_ss, sp_pre_dec(op_bytes),=0A = ®.sel, op_bytes, ctxt)) ||=0A (rc =3D ops->write(= x86_seg_ss, sp_pre_dec(op_bytes),=0A- = &_regs.eip, op_bytes, ctxt)) )=0A+ &_regs.eip,= op_bytes, ctxt)) ||=0A+ (rc =3D ops->write_segment(x86_seg_cs,= &cs, ctxt)) )=0A goto done;=0A =0A- if ( (rc =3D = load_seg(x86_seg_cs, sel, 0, ctxt, ops)) !=3D 0 )=0A- goto = done;=0A _regs.eip =3D eip;=0A break;=0A }=0A@@ = -2664,7 +2692,8 @@ x86_emulate(=0A int offset =3D (b =3D=3D 0xc2) = ? insn_fetch_type(uint16_t) : 0;=0A op_bytes =3D ((op_bytes =3D=3D = 4) && mode_64bit()) ? 8 : op_bytes;=0A if ( (rc =3D read_ulong(x86_= seg_ss, sp_post_inc(op_bytes + offset),=0A- = &dst.val, op_bytes, ctxt, ops)) !=3D 0 )=0A+ = &dst.val, op_bytes, ctxt, ops)) !=3D 0 ||=0A+ (rc =3D = ops->insn_fetch(x86_seg_cs, dst.val, NULL, 0, ctxt)) )=0A goto = done;=0A _regs.eip =3D dst.val;=0A break;=0A@@ -2679,7 = +2708,7 @@ x86_emulate(=0A if ( (rc =3D read_ulong(src.mem.seg, = src.mem.off + src.bytes,=0A &sel, 2, ctxt, = ops)) !=3D 0 )=0A goto done;=0A- if ( (rc =3D load_seg(d= st.val, sel, 0, ctxt, ops)) !=3D 0 )=0A+ if ( (rc =3D load_seg(dst.v= al, sel, 0, NULL, ctxt, ops)) !=3D 0 )=0A goto done;=0A = dst.val =3D src.val;=0A break;=0A@@ -2753,7 +2782,8 @@ x86_emulate= (=0A &dst.val, op_bytes, ctxt, ops)) ||=0A = (rc =3D read_ulong(x86_seg_ss, sp_post_inc(op_bytes + = offset),=0A &src.val, op_bytes, ctxt, ops)) = ||=0A- (rc =3D load_seg(x86_seg_cs, src.val, 1, ctxt, ops)) = )=0A+ (rc =3D load_seg(x86_seg_cs, src.val, 1, &cs, ctxt, = ops)) ||=0A+ (rc =3D commit_far_branch(&cs, dst.val)) )=0A = goto done;=0A _regs.eip =3D dst.val;=0A break;=0A@@= -2782,7 +2812,7 @@ x86_emulate(=0A goto swint;=0A =0A case = 0xcf: /* iret */ {=0A- unsigned long cs, eip, eflags;=0A+ = unsigned long sel, eip, eflags;=0A uint32_t mask =3D EFLG_VIP | = EFLG_VIF | EFLG_VM;=0A if ( !mode_ring0() )=0A mask = |=3D EFLG_IOPL;=0A@@ -2792,7 +2822,7 @@ x86_emulate(=0A if ( (rc = =3D read_ulong(x86_seg_ss, sp_post_inc(op_bytes),=0A = &eip, op_bytes, ctxt, ops)) ||=0A (rc =3D read_ulong(x= 86_seg_ss, sp_post_inc(op_bytes),=0A- &cs, = op_bytes, ctxt, ops)) ||=0A+ &sel, op_bytes, = ctxt, ops)) ||=0A (rc =3D read_ulong(x86_seg_ss, sp_post_inc(o= p_bytes),=0A &eflags, op_bytes, ctxt, ops)) = )=0A goto done;=0A@@ -2802,7 +2832,8 @@ x86_emulate(=0A = _regs.eflags &=3D mask;=0A _regs.eflags |=3D (uint32_t)(eflags & = ~mask) | 0x02;=0A _regs.eip =3D eip;=0A- if ( (rc =3D = load_seg(x86_seg_cs, cs, 1, ctxt, ops)) !=3D 0 )=0A+ if ( (rc =3D = load_seg(x86_seg_cs, sel, 1, &cs, ctxt, ops)) ||=0A+ (rc =3D = commit_far_branch(&cs, eip)) )=0A goto done;=0A = break;=0A }=0A@@ -3432,7 +3463,8 @@ x86_emulate(=0A generate_ex= ception_if(mode_64bit(), EXC_UD, -1);=0A eip =3D insn_fetch_bytes(o= p_bytes);=0A sel =3D insn_fetch_type(uint16_t);=0A- if ( = (rc =3D load_seg(x86_seg_cs, sel, 0, ctxt, ops)) !=3D 0 )=0A+ if ( = (rc =3D load_seg(x86_seg_cs, sel, 0, &cs, ctxt, ops)) ||=0A+ = (rc =3D commit_far_branch(&cs, eip)) )=0A goto done;=0A = _regs.eip =3D eip;=0A break;=0A@@ -3702,10 +3734,14 @@ x86_emulate= (=0A break;=0A case 2: /* call (near) */=0A = dst.val =3D _regs.eip;=0A+ if ( (rc =3D ops->insn_fetch(x86_seg= _cs, src.val, NULL, 0, ctxt)) )=0A+ goto done;=0A = _regs.eip =3D src.val;=0A src.val =3D dst.val;=0A = goto push;=0A case 4: /* jmp (near) */=0A+ if ( (rc = =3D ops->insn_fetch(x86_seg_cs, src.val, NULL, 0, ctxt)) )=0A+ = goto done;=0A _regs.eip =3D src.val;=0A = dst.type =3D OP_NONE;=0A break;=0A@@ -3724,14 +3760,17 @@ = x86_emulate(=0A struct segment_register reg;=0A = fail_if(ops->read_segment =3D=3D NULL);=0A if ( (rc = =3D ops->read_segment(x86_seg_cs, ®, ctxt)) ||=0A- = (rc =3D ops->write(x86_seg_ss, sp_pre_dec(op_bytes),=0A+ = (rc =3D load_seg(x86_seg_cs, sel, 0, &cs, ctxt, ops)) ||=0A+ = (validate_far_branch(&cs, src.val),=0A+ rc = =3D ops->write(x86_seg_ss, sp_pre_dec(op_bytes),=0A = ®.sel, op_bytes, ctxt)) ||=0A (rc = =3D ops->write(x86_seg_ss, sp_pre_dec(op_bytes),=0A- = &_regs.eip, op_bytes, ctxt)) )=0A+ = &_regs.eip, op_bytes, ctxt)) ||=0A+ (rc = =3D ops->write_segment(x86_seg_cs, &cs, ctxt)) )=0A = goto done;=0A }=0A-=0A- if ( (rc =3D load_seg(x86_se= g_cs, sel, 0, ctxt, ops)) !=3D 0 )=0A+ else if ( (rc =3D = load_seg(x86_seg_cs, sel, 0, &cs, ctxt, ops)) ||=0A+ = (rc =3D commit_far_branch(&cs, src.val)) )=0A goto = done;=0A _regs.eip =3D src.val;=0A =0A@@ -3816,7 +3855,7 @@ = x86_emulate(=0A generate_exception_if(!in_protmode(ctxt, ops), = EXC_UD, -1);=0A generate_exception_if(!mode_ring0(), EXC_GP, = 0);=0A if ( (rc =3D load_seg((modrm_reg & 1) ? x86_seg_tr : = x86_seg_ldtr,=0A- src.val, 0, ctxt, ops)) !=3D = 0 )=0A+ src.val, 0, NULL, ctxt, ops)) !=3D 0 = )=0A goto done;=0A break;=0A =0A@@ -4269,6 +4308,9 @@ = x86_emulate(=0A goto done;=0A =0A generate_exception_if= (!(msr_content & 0xfffc), EXC_GP, 0);=0A+ generate_exception_if(user= 64 && (!is_canonical_address(_regs.edx) ||=0A+ = !is_canonical_address(_regs.ecx)),=0A+ = EXC_GP, 0);=0A =0A cs.sel =3D (msr_content | 3) + /* = SELECTOR_RPL_MASK */=0A (user64 ? 32 : 16);=0A --=__Part2611B97D.2__= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel --=__Part2611B97D.2__=--