> -----Original Message----- > From: Andrew Cooper [mailto:andrew.coop...@citrix.com] > Sent: 23 November 2016 15:39 > To: Xen-devel <xen-devel@lists.xen.org> > Cc: Andrew Cooper <andrew.coop...@citrix.com>; Jan Beulich > <jbeul...@suse.com>; Paul Durrant <paul.durr...@citrix.com> > Subject: [PATCH 14/15] x86/hvm: Prepare to allow use of system segments > for memory references > > All system segments (GDT/IDT/LDT and TR) describe a linear address and > limit, > and act similarly to user segments. However all current uses of these tables > in the emulator opencode the address calculations and limit checks. In > particular, no care is taken for access which wrap around the 4GB or > non-canonical boundaries. > > Alter hvm_virtual_to_linear_addr() to cope with performing segmentation > checks > on system segments. This involves restricting access checks in the 32bit case > to user segments only, and adding presence/limit checks in the 64bit case. > > When suffering a segmentation fault for a system segments, return > X86EMUL_EXCEPTION but leave the fault injection to the caller. The fault > type > depends on the higher level action being performed. > > Signed-off-by: Andrew Cooper <andrew.coop...@citrix.com> > Signed-off-by: Jan Beulich <jbeul...@suse.com> > Reviewed-by: George Dunlap <george.dun...@citrix.com> > --- > CC: Paul Durrant <paul.durr...@citrix.com>
Reviewed-by: Paul Durrant <paul.durr...@citrix.com> > --- > xen/arch/x86/hvm/emulate.c | 14 ++++++++---- > xen/arch/x86/hvm/hvm.c | 40 ++++++++++++++++++++++----------- > - > xen/arch/x86/mm/shadow/common.c | 12 +++++++--- > xen/arch/x86/x86_emulate/x86_emulate.h | 26 ++++++++++++++-------- > 4 files changed, 62 insertions(+), 30 deletions(-) > > diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c > index c248eca..3a7d1f3 100644 > --- a/xen/arch/x86/hvm/emulate.c > +++ b/xen/arch/x86/hvm/emulate.c > @@ -567,10 +567,16 @@ static int hvmemul_virtual_to_linear( > if ( *reps != 1 ) > return X86EMUL_UNHANDLEABLE; > > - /* This is a singleton operation: fail it with an exception. */ > - x86_emul_hw_exception((seg == x86_seg_ss) > - ? TRAP_stack_error > - : TRAP_gp_fault, 0, &hvmemul_ctxt->ctxt); > + /* > + * Leave exception injection to the caller for non-user segments: We > + * neither know the exact error code to be used, nor can we easily > + * determine the kind of exception (#GP or #TS) in that case. > + */ > + if ( is_x86_user_segment(seg) ) > + x86_emul_hw_exception((seg == x86_seg_ss) > + ? TRAP_stack_error > + : TRAP_gp_fault, 0, &hvmemul_ctxt->ctxt); > + > return X86EMUL_EXCEPTION; > } > > diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c > index e1f2c9e..2bcef1f 100644 > --- a/xen/arch/x86/hvm/hvm.c > +++ b/xen/arch/x86/hvm/hvm.c > @@ -2497,24 +2497,28 @@ bool_t hvm_virtual_to_linear_addr( > if ( !reg->attr.fields.p ) > goto out; > > - switch ( access_type ) > + /* Read/write restrictions only exist for user segments. */ > + if ( reg->attr.fields.s ) > { > - case hvm_access_read: > - if ( (reg->attr.fields.type & 0xa) == 0x8 ) > - goto out; /* execute-only code segment */ > - break; > - case hvm_access_write: > - if ( (reg->attr.fields.type & 0xa) != 0x2 ) > - goto out; /* not a writable data segment */ > - break; > - default: > - break; > + switch ( access_type ) > + { > + case hvm_access_read: > + if ( (reg->attr.fields.type & 0xa) == 0x8 ) > + goto out; /* execute-only code segment */ > + break; > + case hvm_access_write: > + if ( (reg->attr.fields.type & 0xa) != 0x2 ) > + goto out; /* not a writable data segment */ > + break; > + default: > + break; > + } > } > > last_byte = (uint32_t)offset + bytes - !!bytes; > > /* Is this a grows-down data segment? Special limit check if so. */ > - if ( (reg->attr.fields.type & 0xc) == 0x4 ) > + if ( reg->attr.fields.s && (reg->attr.fields.type & 0xc) == 0x4 ) > { > /* Is upper limit 0xFFFF or 0xFFFFFFFF? */ > if ( !reg->attr.fields.db ) > @@ -2530,10 +2534,18 @@ bool_t hvm_virtual_to_linear_addr( > else > { > /* > - * LONG MODE: FS and GS add segment base. Addresses must be > canonical. > + * User segments are always treated as present. System segment may > + * not be, and also incur limit checks. > */ > + if ( is_x86_system_segment(seg) && > + (!reg->attr.fields.p || (offset + bytes - !!bytes) > > reg->limit) ) > + goto out; > > - if ( (seg == x86_seg_fs) || (seg == x86_seg_gs) ) > + /* > + * LONG MODE: FS, GS and system segments: add segment base. All > + * addresses must be canonical. > + */ > + if ( seg >= x86_seg_fs ) > addr += reg->base; > > last_byte = addr + bytes - !!bytes; > diff --git a/xen/arch/x86/mm/shadow/common.c > b/xen/arch/x86/mm/shadow/common.c > index 88d4642..954c157 100644 > --- a/xen/arch/x86/mm/shadow/common.c > +++ b/xen/arch/x86/mm/shadow/common.c > @@ -162,9 +162,15 @@ static int hvm_translate_linear_addr( > > if ( !okay ) > { > - x86_emul_hw_exception( > - (seg == x86_seg_ss) ? TRAP_stack_error : TRAP_gp_fault, > - 0, &sh_ctxt->ctxt); > + /* > + * Leave exception injection to the caller for non-user segments: We > + * neither know the exact error code to be used, nor can we easily > + * determine the kind of exception (#GP or #TS) in that case. > + */ > + if ( is_x86_user_segment(seg) ) > + x86_emul_hw_exception( > + (seg == x86_seg_ss) ? TRAP_stack_error : TRAP_gp_fault, > + 0, &sh_ctxt->ctxt); > return X86EMUL_EXCEPTION; > } > > diff --git a/xen/arch/x86/x86_emulate/x86_emulate.h > b/xen/arch/x86/x86_emulate/x86_emulate.h > index cc26e9d..4d18623 100644 > --- a/xen/arch/x86/x86_emulate/x86_emulate.h > +++ b/xen/arch/x86/x86_emulate/x86_emulate.h > @@ -27,7 +27,11 @@ > > struct x86_emulate_ctxt; > > -/* Comprehensive enumeration of x86 segment registers. */ > +/* > + * Comprehensive enumeration of x86 segment registers. Various bits of > code > + * rely on this order (general purpose before system, tr at the beginning of > + * system). > + */ > enum x86_segment { > /* General purpose. Matches the SReg3 encoding in opcode/ModRM > bytes. */ > x86_seg_es, > @@ -36,21 +40,25 @@ enum x86_segment { > x86_seg_ds, > x86_seg_fs, > x86_seg_gs, > - /* System. */ > + /* System: Valid to use for implicit table references. */ > x86_seg_tr, > x86_seg_ldtr, > x86_seg_gdtr, > x86_seg_idtr, > - /* > - * Dummy: used to emulate direct processor accesses to management > - * structures (TSS, GDT, LDT, IDT, etc.) which use linear addressing > - * (no segment component) and bypass usual segment- and page-level > - * protection checks. > - */ > + /* No Segment: For accesses which are already linear. */ > x86_seg_none > }; > > -#define is_x86_user_segment(seg) ((unsigned)(seg) <= x86_seg_gs) > +static inline bool is_x86_user_segment(enum x86_segment seg) > +{ > + unsigned int idx = seg; > + > + return idx <= x86_seg_gs; > +} > +static inline bool is_x86_system_segment(enum x86_segment seg) > +{ > + return seg >= x86_seg_tr && seg < x86_seg_none; > +} > > /* Classification of the types of software generated interrupts/exceptions. > */ > enum x86_swint_type { > -- > 2.1.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel