[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen master] x86/emul: Prepare to allow use of system segments for memory references
commit c785f759718b0a86a0b1332901d1ee63c9e67c77 Author: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> AuthorDate: Thu Jun 30 23:55:33 2016 +0100 Commit: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> CommitDate: Fri Dec 2 17:23:02 2016 +0000 x86/emul: 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.cooper3@xxxxxxxxxx> Reviewed-by: Jan Beulich <JBeulich@xxxxxxxx> Reviewed-by: George Dunlap <george.dunlap@xxxxxxxxxx> Reviewed-by: Paul Durrant <paul.durrant@xxxxxxxxxx> --- 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 ccf3aa2..d0a043b 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 27896ec..504425a 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 c59f022..39be564 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 915c1fe..164fc24 100644 --- a/xen/arch/x86/x86_emulate/x86_emulate.h +++ b/xen/arch/x86/x86_emulate/x86_emulate.h @@ -31,7 +31,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, @@ -40,21 +44,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 { -- generated by git-patchbot for /home/xen/git/xen.git#master _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxx https://lists.xenproject.org/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |