> -----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

Reply via email to