ia64/xen-unstable

changeset 11282:51a98a6c2c05

[XEN] Fix the x86 emulator to safely fail when it turns out the
faulting memory access was to/from an implicit memory operand
(typically either an instruction fetch or stack access).
Rationalise use of macros for page fault error code flags.
This patch supercedes the fix in changeset 11242.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Wed Aug 23 18:38:08 2006 +0100 (2006-08-23)
parents d389123fad85
children 551495fa7b3e
files tools/tests/test_x86_emulator.c xen/arch/x86/shadow2.c xen/arch/x86/traps.c xen/arch/x86/x86_emulate.c xen/include/asm-x86/processor.h xen/include/asm-x86/shadow2-types.h
line diff
     1.1 --- a/tools/tests/test_x86_emulator.c	Wed Aug 23 17:25:11 2006 +0100
     1.2 +++ b/tools/tests/test_x86_emulator.c	Wed Aug 23 18:38:08 2006 +0100
     1.3 @@ -15,6 +15,8 @@ typedef int64_t            s64;
     1.4  #include <asm-x86/x86_emulate.h>
     1.5  #include <sys/mman.h>
     1.6  
     1.7 +#define PFEC_write_access (1U<<1)
     1.8 +
     1.9  static int read_any(
    1.10      unsigned long addr,
    1.11      unsigned long *val,
    1.12 @@ -105,6 +107,7 @@ int main(int argc, char **argv)
    1.13      regs.eflags = 0x200;
    1.14      regs.eip    = (unsigned long)&instr[0];
    1.15      regs.ecx    = 0x12345678;
    1.16 +    regs.error_code = PFEC_write_access;
    1.17      ctxt.cr2    = (unsigned long)res;
    1.18      *res        = 0x7FFFFFFF;
    1.19      rc = x86_emulate_memop(&ctxt, &emulops);
    1.20 @@ -125,6 +128,7 @@ int main(int argc, char **argv)
    1.21      regs.ecx    = 0x12345678UL;
    1.22  #endif
    1.23      ctxt.cr2    = (unsigned long)res;
    1.24 +    regs.error_code = 0;
    1.25      rc = x86_emulate_memop(&ctxt, &emulops);
    1.26      if ( (rc != 0) || 
    1.27           (*res != 0x92345677) || 
    1.28 @@ -139,6 +143,7 @@ int main(int argc, char **argv)
    1.29      regs.eip    = (unsigned long)&instr[0];
    1.30      regs.ecx    = ~0UL;
    1.31      ctxt.cr2    = (unsigned long)res;
    1.32 +    regs.error_code = 0;
    1.33      rc = x86_emulate_memop(&ctxt, &emulops);
    1.34      if ( (rc != 0) || 
    1.35           (*res != 0x92345677) || 
    1.36 @@ -154,6 +159,7 @@ int main(int argc, char **argv)
    1.37      regs.eax    = 0x92345677UL;
    1.38      regs.ecx    = 0xAA;
    1.39      ctxt.cr2    = (unsigned long)res;
    1.40 +    regs.error_code = PFEC_write_access;
    1.41      rc = x86_emulate_memop(&ctxt, &emulops);
    1.42      if ( (rc != 0) || 
    1.43           (*res != 0x923456AA) || 
    1.44 @@ -170,6 +176,7 @@ int main(int argc, char **argv)
    1.45      regs.eax    = 0xAABBCC77UL;
    1.46      regs.ecx    = 0xFF;
    1.47      ctxt.cr2    = (unsigned long)res;
    1.48 +    regs.error_code = PFEC_write_access;
    1.49      rc = x86_emulate_memop(&ctxt, &emulops);
    1.50      if ( (rc != 0) || 
    1.51           (*res != 0x923456AA) || 
    1.52 @@ -186,6 +193,7 @@ int main(int argc, char **argv)
    1.53      regs.eip    = (unsigned long)&instr[0];
    1.54      regs.ecx    = 0x12345678;
    1.55      ctxt.cr2    = (unsigned long)res;
    1.56 +    regs.error_code = PFEC_write_access;
    1.57      rc = x86_emulate_memop(&ctxt, &emulops);
    1.58      if ( (rc != 0) || 
    1.59           (*res != 0x12345678) || 
    1.60 @@ -203,6 +211,7 @@ int main(int argc, char **argv)
    1.61      regs.eax    = 0x923456AAUL;
    1.62      regs.ecx    = 0xDDEEFF00L;
    1.63      ctxt.cr2    = (unsigned long)res;
    1.64 +    regs.error_code = PFEC_write_access;
    1.65      rc = x86_emulate_memop(&ctxt, &emulops);
    1.66      if ( (rc != 0) || 
    1.67           (*res != 0xDDEEFF00) || 
    1.68 @@ -240,6 +249,7 @@ int main(int argc, char **argv)
    1.69      regs.eip    = (unsigned long)&instr[0];
    1.70      regs.edi    = (unsigned long)res;
    1.71      ctxt.cr2    = regs.edi;
    1.72 +    regs.error_code = PFEC_write_access;
    1.73      rc = x86_emulate_memop(&ctxt, &emulops);
    1.74      if ( (rc != 0) || 
    1.75           (*res != 0x2233445D) ||
    1.76 @@ -261,6 +271,7 @@ int main(int argc, char **argv)
    1.77      regs.eip    = (unsigned long)&instr[0];
    1.78      regs.edi    = (unsigned long)res;
    1.79      ctxt.cr2    = regs.edi;
    1.80 +    regs.error_code = PFEC_write_access;
    1.81      rc = x86_emulate_memop(&ctxt, &emulops);
    1.82      if ( (rc != 0) || 
    1.83           (res[0] != 0x9999AAAA) ||
    1.84 @@ -275,6 +286,7 @@ int main(int argc, char **argv)
    1.85      regs.eip    = (unsigned long)&instr[0];
    1.86      regs.edi    = (unsigned long)res;
    1.87      ctxt.cr2    = regs.edi;
    1.88 +    regs.error_code = PFEC_write_access;
    1.89      rc = x86_emulate_memop(&ctxt, &emulops);
    1.90      if ( (rc != 0) || 
    1.91           (res[0] != 0x9999AAAA) ||
    1.92 @@ -292,6 +304,7 @@ int main(int argc, char **argv)
    1.93      regs.ecx    = 0x12345678;
    1.94      ctxt.cr2    = (unsigned long)res;
    1.95      *res        = 0x82;
    1.96 +    regs.error_code = 0;
    1.97      rc = x86_emulate_memop(&ctxt, &emulops);
    1.98      if ( (rc != 0) ||
    1.99           (*res != 0x82) ||
   1.100 @@ -307,6 +320,7 @@ int main(int argc, char **argv)
   1.101      regs.ecx    = 0x12345678;
   1.102      ctxt.cr2    = (unsigned long)res;
   1.103      *res        = 0x1234aa82;
   1.104 +    regs.error_code = 0;
   1.105      rc = x86_emulate_memop(&ctxt, &emulops);
   1.106      if ( (rc != 0) ||
   1.107           (*res != 0x1234aa82) ||
     2.1 --- a/xen/arch/x86/shadow2.c	Wed Aug 23 17:25:11 2006 +0100
     2.2 +++ b/xen/arch/x86/shadow2.c	Wed Aug 23 18:38:08 2006 +0100
     2.3 @@ -2893,7 +2893,7 @@ static int sh2_page_fault(struct vcpu *v
     2.4      // i.e. ring 3.  Such errors are not caused or dealt with by the shadow
     2.5      // code.
     2.6      //
     2.7 -    if ( (regs->error_code & X86_PFEC_SUPERVISOR_FAULT) &&
     2.8 +    if ( (regs->error_code & PFEC_user_mode) &&
     2.9           !(accumulated_gflags & _PAGE_USER) )
    2.10      {
    2.11          /* illegal user-mode access to supervisor-only page */
    2.12 @@ -2903,7 +2903,7 @@ static int sh2_page_fault(struct vcpu *v
    2.13  
    2.14      // Was it a write fault?
    2.15      //
    2.16 -    if ( regs->error_code & X86_PFEC_WRITE_FAULT )
    2.17 +    if ( regs->error_code & PFEC_write_access )
    2.18      {
    2.19          if ( unlikely(!(accumulated_gflags & _PAGE_RW)) )
    2.20          {
    2.21 @@ -2917,7 +2917,7 @@ static int sh2_page_fault(struct vcpu *v
    2.22          // marked "do not execute".  Such errors are not caused or dealt with
    2.23          // by the shadow code.
    2.24          //
    2.25 -        if ( regs->error_code & X86_PFEC_INSN_FETCH_FAULT )
    2.26 +        if ( regs->error_code & PFEC_insn_fetch )
    2.27          {
    2.28              if ( accumulated_gflags & _PAGE_NX_BIT )
    2.29              {
    2.30 @@ -2960,8 +2960,8 @@ static int sh2_page_fault(struct vcpu *v
    2.31       * for the shadow entry, since we might promote a page here. */
    2.32      // XXX -- this code will need to change somewhat if/when the shadow code
    2.33      // can directly map superpages...
    2.34 -    ft = ((regs->error_code & X86_PFEC_WRITE_FAULT) 
    2.35 -          ? ft_demand_write : ft_demand_read);
    2.36 +    ft = ((regs->error_code & PFEC_write_access) ?
    2.37 +          ft_demand_write : ft_demand_read);
    2.38      ptr_sl1e = shadow_get_and_create_l1e(v, &gw, &sl1mfn, ft);
    2.39      ASSERT(ptr_sl1e);
    2.40  
     3.1 --- a/xen/arch/x86/traps.c	Wed Aug 23 17:25:11 2006 +0100
     3.2 +++ b/xen/arch/x86/traps.c	Wed Aug 23 18:38:08 2006 +0100
     3.3 @@ -686,9 +686,9 @@ void propagate_page_fault(unsigned long 
     3.4      v->vcpu_info->arch.cr2           = addr;
     3.5  
     3.6      /* Re-set error_code.user flag appropriately for the guest. */
     3.7 -    error_code &= ~PGERR_user_mode;
     3.8 +    error_code &= ~PFEC_user_mode;
     3.9      if ( !guest_kernel_mode(v, guest_cpu_user_regs()) )
    3.10 -        error_code |= PGERR_user_mode;
    3.11 +        error_code |= PFEC_user_mode;
    3.12  
    3.13      ti = &v->arch.guest_context.trap_ctxt[TRAP_page_fault];
    3.14      tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE;
    3.15 @@ -768,17 +768,17 @@ static int __spurious_page_fault(
    3.16      unsigned int required_flags, disallowed_flags;
    3.17  
    3.18      /* Reserved bit violations are never spurious faults. */
    3.19 -    if ( regs->error_code & PGERR_reserved_bit )
    3.20 +    if ( regs->error_code & PFEC_reserved_bit )
    3.21          return 0;
    3.22  
    3.23      required_flags  = _PAGE_PRESENT;
    3.24 -    if ( regs->error_code & PGERR_write_access )
    3.25 +    if ( regs->error_code & PFEC_write_access )
    3.26          required_flags |= _PAGE_RW;
    3.27 -    if ( regs->error_code & PGERR_user_mode )
    3.28 +    if ( regs->error_code & PFEC_user_mode )
    3.29          required_flags |= _PAGE_USER;
    3.30  
    3.31      disallowed_flags = 0;
    3.32 -    if ( regs->error_code & PGERR_instr_fetch )
    3.33 +    if ( regs->error_code & PFEC_insn_fetch )
    3.34          disallowed_flags |= _PAGE_NX;
    3.35  
    3.36      mfn = cr3 >> PAGE_SHIFT;
    3.37 @@ -886,7 +886,7 @@ static int fixup_page_fault(unsigned lon
    3.38           guest_kernel_mode(v, regs) &&
    3.39           /* Do not check if access-protection fault since the page may 
    3.40              legitimately be not present in shadow page tables */
    3.41 -         ((regs->error_code & PGERR_write_access) == PGERR_write_access) &&
    3.42 +         ((regs->error_code & PFEC_write_access) == PFEC_write_access) &&
    3.43           ptwr_do_page_fault(d, addr, regs) )
    3.44          return EXCRET_fault_fixed;
    3.45  
    3.46 @@ -1100,7 +1100,7 @@ static int emulate_privileged_op(struct 
    3.47              if ( (rc = copy_to_user((void *)regs->edi, &data, op_bytes)) != 0 )
    3.48              {
    3.49                  propagate_page_fault(regs->edi + op_bytes - rc,
    3.50 -                                     PGERR_write_access);
    3.51 +                                     PFEC_write_access);
    3.52                  return EXCRET_fault_fixed;
    3.53              }
    3.54              regs->edi += (int)((regs->eflags & EF_DF) ? -op_bytes : op_bytes);
     4.1 --- a/xen/arch/x86/x86_emulate.c	Wed Aug 23 17:25:11 2006 +0100
     4.2 +++ b/xen/arch/x86/x86_emulate.c	Wed Aug 23 18:38:08 2006 +0100
     4.3 @@ -21,6 +21,11 @@
     4.4  #endif
     4.5  #include <asm-x86/x86_emulate.h>
     4.6  
     4.7 +#ifndef PFEC_write_access
     4.8 +#define PFEC_write_access (1U<<1)
     4.9 +#define PFEC_insn_fetch   (1U<<4)
    4.10 +#endif
    4.11 +
    4.12  /*
    4.13   * Opcode effective-address decode tables.
    4.14   * Note that we only emulate instructions that have at least one memory
    4.15 @@ -444,6 +449,13 @@ x86_emulate_memop(
    4.16      /* Shadow copy of register state. Committed on successful emulation. */
    4.17      struct cpu_user_regs _regs = *ctxt->regs;
    4.18  
    4.19 +    /*
    4.20 +     * We do not emulate faults on instruction fetch. We assume that the
    4.21 +     * guest never executes out of a special memory area.
    4.22 +     */
    4.23 +    if ( _regs.error_code & PFEC_insn_fetch )
    4.24 +        return -1;
    4.25 +
    4.26      switch ( mode )
    4.27      {
    4.28      case X86EMUL_MODE_REAL:
    4.29 @@ -620,6 +632,14 @@ x86_emulate_memop(
    4.30          }
    4.31          break;
    4.32      case DstMem:
    4.33 +        /*
    4.34 +         * We expect that the fault occurred while accessing the explicit
    4.35 +         * destination memory operand. This is clearly not the case if the
    4.36 +         * fault occurred on a read access (eg. POP has an *implicit* operand
    4.37 +         * but we expect that the guest never uses special memory as stack).
    4.38 +         */
    4.39 +        if ( !(_regs.error_code & PFEC_write_access) )
    4.40 +            goto cannot_emulate;
    4.41          dst.type  = OP_MEM;
    4.42          dst.ptr   = (unsigned long *)cr2;
    4.43          dst.bytes = (d & ByteOp) ? 1 : op_bytes;
    4.44 @@ -664,6 +684,14 @@ x86_emulate_memop(
    4.45      case SrcMem:
    4.46          src.bytes = (d & ByteOp) ? 1 : op_bytes;
    4.47      srcmem_common:
    4.48 +        /*
    4.49 +         * We expect that the fault occurred while accessing the explicit
    4.50 +         * source memory operand. This is clearly not the case if the fault
    4.51 +         * occurred on a write access (eg. PUSH has an *implicit* operand
    4.52 +         * but we expect that the guest never uses special memory as stack).
    4.53 +         */
    4.54 +        if ( _regs.error_code & PFEC_write_access )
    4.55 +            goto cannot_emulate;
    4.56          src.type  = OP_MEM;
    4.57          src.ptr   = (unsigned long *)cr2;
    4.58          if ( (rc = ops->read_emulated((unsigned long)src.ptr, 
    4.59 @@ -846,9 +874,6 @@ x86_emulate_memop(
    4.60              emulate_1op("dec", dst, _regs.eflags);
    4.61              break;
    4.62          case 6: /* push */
    4.63 -            /* Don't emulate if fault was on stack */
    4.64 -            if ( _regs.error_code & 2 )
    4.65 -                goto cannot_emulate; 
    4.66              /* 64-bit mode: PUSH always pushes a 64-bit operand. */
    4.67              if ( mode == X86EMUL_MODE_PROT64 )
    4.68              {
    4.69 @@ -923,7 +948,7 @@ x86_emulate_memop(
    4.70      case 0xa4 ... 0xa5: /* movs */
    4.71          dst.type  = OP_MEM;
    4.72          dst.bytes = (d & ByteOp) ? 1 : op_bytes;
    4.73 -        if ( _regs.error_code & 2 )
    4.74 +        if ( _regs.error_code & PFEC_write_access )
    4.75          {
    4.76              /* Write fault: destination is special memory. */
    4.77              dst.ptr = (unsigned long *)cr2;
    4.78 @@ -1165,7 +1190,7 @@ x86_emulate_write_std(
    4.79  
    4.80      if ( (rc = copy_to_user((void *)addr, (void *)&val, bytes)) != 0 )
    4.81      {
    4.82 -        propagate_page_fault(addr + bytes - rc, PGERR_write_access);
    4.83 +        propagate_page_fault(addr + bytes - rc, PFEC_write_access);
    4.84          return X86EMUL_PROPAGATE_FAULT;
    4.85      }
    4.86  
     5.1 --- a/xen/include/asm-x86/processor.h	Wed Aug 23 17:25:11 2006 +0100
     5.2 +++ b/xen/include/asm-x86/processor.h	Wed Aug 23 18:38:08 2006 +0100
     5.3 @@ -130,11 +130,11 @@
     5.4  #define TF_kernel_mode         (1<<_TF_kernel_mode)
     5.5  
     5.6  /* #PF error code values. */
     5.7 -#define PGERR_page_present   (1U<<0)
     5.8 -#define PGERR_write_access   (1U<<1)
     5.9 -#define PGERR_user_mode      (1U<<2)
    5.10 -#define PGERR_reserved_bit   (1U<<3)
    5.11 -#define PGERR_instr_fetch    (1U<<4)
    5.12 +#define PFEC_page_present   (1U<<0)
    5.13 +#define PFEC_write_access   (1U<<1)
    5.14 +#define PFEC_user_mode      (1U<<2)
    5.15 +#define PFEC_reserved_bit   (1U<<3)
    5.16 +#define PFEC_insn_fetch     (1U<<4)
    5.17  
    5.18  #ifndef __ASSEMBLY__
    5.19  
     6.1 --- a/xen/include/asm-x86/shadow2-types.h	Wed Aug 23 17:25:11 2006 +0100
     6.2 +++ b/xen/include/asm-x86/shadow2-types.h	Wed Aug 23 18:38:08 2006 +0100
     6.3 @@ -461,19 +461,6 @@ struct shadow2_walk_t
     6.4      mfn_t l1mfn;                /* MFN that the level 1 entry is in */
     6.5  };
     6.6  
     6.7 -
     6.8 -/* X86 error code bits:
     6.9 - * These bits certainly ought to be defined somewhere other than here,
    6.10 - * but until that place is determined, here they sit.
    6.11 - *
    6.12 - * "PFEC" == "Page Fault Error Code"
    6.13 - */
    6.14 -#define X86_PFEC_PRESENT            1  /* 0 == page was not present */
    6.15 -#define X86_PFEC_WRITE_FAULT        2  /* 0 == reading, 1 == writing */
    6.16 -#define X86_PFEC_SUPERVISOR_FAULT   4  /* 0 == supervisor-mode, 1 == user */
    6.17 -#define X86_PFEC_RESERVED_BIT_FAULT 8  /* 1 == reserved bits set in pte */
    6.18 -#define X86_PFEC_INSN_FETCH_FAULT  16  /* 0 == normal, 1 == instr'n fetch */
    6.19 -
    6.20  /* macros for dealing with the naming of the internal function names of the
    6.21   * shadow code's external entry points.
    6.22   */