File 5b8d5832-x86-assorted-array_index_nospec-insertions.patch of Package xen.10697

# Commit 3f2002614af51dfd507168a1696658bac91155ce
# Date 2018-09-03 17:50:10 +0200
# Author Jan Beulich <jbeulich@suse.com>
# Committer Jan Beulich <jbeulich@suse.com>
x86: assorted array_index_nospec() insertions

Don't chance having Spectre v1 (including BCBS) gadgets. In some of the
cases the insertions are more of precautionary nature rather than there
provably being a gadget, but I think we should err on the safe (secure)
side here.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Paul Durrant <paul.durrant@citrix.com>
Acked-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>

--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -31,6 +31,7 @@
 #include <xen/domain_page.h>
 #include <xen/hypercall.h>
 #include <xen/guest_access.h>
+#include <xen/nospec.h>
 #include <xen/event.h>
 #include <xen/paging.h>
 #include <xen/cpu.h>
@@ -3898,9 +3899,16 @@ int hvm_do_hypercall(struct cpu_user_reg
     if ( (eax & 0x80000000) && is_viridian_domain(curr->domain) )
         return viridian_hypercall(regs);
 
-    if ( (eax >= NR_hypercalls) ||
-         (is_pvh_vcpu(curr) ? !pvh_hypercall64_table[eax]
-                            : !hvm_hypercall32_table[eax]) )
+    if ( eax >= NR_hypercalls )
+    {
+        regs->eax = -ENOSYS;
+        return HVM_HCALL_completed;
+    }
+
+    eax = array_index_nospec(eax, NR_hypercalls);
+
+    if ( is_pvh_vcpu(curr) ? !pvh_hypercall64_table[eax]
+                           : !hvm_hypercall32_table[eax] )
     {
         regs->eax = -ENOSYS;
         return HVM_HCALL_completed;
@@ -4771,6 +4779,7 @@ long do_hvm_op(unsigned long op, XEN_GUE
     {
         struct xen_hvm_set_mem_type a;
         struct domain *d;
+        unsigned int mem_type;
         
         /* Interface types to internal p2m types */
         static const p2m_type_t memtype[] = {
@@ -4800,7 +4809,8 @@ long do_hvm_op(unsigned long op, XEN_GUE
              ((a.first_pfn + a.nr - 1) > domain_get_maximum_gpfn(d)) )
             goto param_fail4;
             
-        if ( a.hvmmem_type >= ARRAY_SIZE(memtype) )
+        mem_type = array_index_nospec(a.hvmmem_type, ARRAY_SIZE(memtype));
+        if ( mem_type >= ARRAY_SIZE(memtype) )
             goto param_fail4;
 
         while ( a.nr )
@@ -4824,21 +4834,21 @@ long do_hvm_op(unsigned long op, XEN_GUE
                 goto param_fail4;
             } 
             if ( !p2m_is_ram(t) &&
-                 (!p2m_is_hole(t) || a.hvmmem_type != HVMMEM_mmio_dm) )
+                 (!p2m_is_hole(t) || mem_type != HVMMEM_mmio_dm) )
             {
                 put_gfn(d, pfn);
                 goto param_fail4;
             }
             else
             {
-                nt = p2m_change_type(d, pfn, t, memtype[a.hvmmem_type]);
+                nt = p2m_change_type(d, pfn, t, memtype[mem_type]);
                 if ( nt != t )
                 {
                     put_gfn(d, pfn);
                     gdprintk(XENLOG_WARNING,
                              "type of pfn %#lx changed from %d to %d while "
                              "we were trying to change it to %d\n",
-                             pfn, t, nt, memtype[a.hvmmem_type]);
+                             pfn, t, nt, memtype[mem_type]);
                     goto param_fail4;
                 }
             }
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -30,6 +30,7 @@
 #include <asm/p2m.h>
 #include <asm/hvm/vmx/vmx.h> /* ept_p2m_init() */
 #include <xen/iommu.h>
+#include <xen/nospec.h>
 #include <asm/mem_event.h>
 #include <public/mem_event.h>
 #include <asm/mem_sharing.h>
@@ -1423,6 +1424,7 @@ long p2m_set_mem_access(struct domain *d
     if ( (unsigned) access >= HVMMEM_access_default )
         return -EINVAL;
 
+    access = array_index_nospec(access, ARRAY_SIZE(memaccess));
     a = memaccess[access];
 
     /* If request to set default access */
--- a/xen/arch/x86/x86_64/compat/entry.S
+++ b/xen/arch/x86/x86_64/compat/entry.S
@@ -31,12 +31,13 @@ UNLIKELY_END(msi_check)
 
         cmpl  $NR_hypercalls,%eax
         jae   compat_bad_hypercall
+        sbbl  %r8d,%r8d              /* array_index_mask_nospec() */
+        andl  %r8d,%eax
 #ifndef NDEBUG
         /* Deliberately corrupt parameter regs not used by this hypercall. */
         pushq UREGS_rbx(%rsp); pushq %rcx; pushq %rdx; pushq %rsi; pushq %rdi
         pushq UREGS_rbp+5*8(%rsp)
         leaq  compat_hypercall_args_table(%rip),%r10
-        movl  %eax,%eax
         movl  $6,%ecx
         subb  (%r10,%rax,1),%cl
         movq  %rsp,%rdi
@@ -51,7 +52,6 @@ UNLIKELY_END(msi_check)
 #define SHADOW_BYTES 16 /* Shadow EIP + shadow hypercall # */
 #else
         /* Relocate argument registers and zero-extend to 64 bits. */
-        movl  %eax,%eax              /* Hypercall #  */
         xchgl %ecx,%esi              /* Arg 2, Arg 4 */
         movl  %edx,%edx              /* Arg 3        */
         movl  %edi,%r8d              /* Arg 5        */
@@ -61,6 +61,7 @@ UNLIKELY_END(msi_check)
 #endif
         cmpb  $0,tb_init_done(%rip)
 UNLIKELY_START(ne, compat_trace)
+        movl  %eax,UREGS_rax+SHADOW_BYTES(%rsp)   /* Hypercall #  */
         call  __trace_hypercall_entry
         /* Restore the registers that __trace_hypercall_entry clobbered. */
         movl  UREGS_rax+SHADOW_BYTES(%rsp),%eax   /* Hypercall #  */
--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -210,6 +210,8 @@ ENTRY(syscall_enter)
         LOAD_C_CLOBBERED cx=0
         cmpq  $NR_hypercalls,%rax
         jae   bad_hypercall
+        sbbq  %r10,%r10              /* array_index_mask_nospec() */
+        andq  %r10,%rax
 #ifndef NDEBUG
         /* Deliberately corrupt parameter regs not used by this hypercall. */
         pushq %rdi; pushq %rsi; pushq %rdx; pushq %rcx; pushq %r8 ; pushq %r9 
@@ -229,6 +231,7 @@ ENTRY(syscall_enter)
 #endif
         cmpb  $0,tb_init_done(%rip)
 UNLIKELY_START(ne, trace)
+        movq  %rax,UREGS_rax+SHADOW_BYTES(%rsp)   /* Hypercall #  */
         call  __trace_hypercall_entry
         /* Restore the registers that __trace_hypercall_entry clobbered. */
         movq  UREGS_rax+SHADOW_BYTES(%rsp),%rax   /* Hypercall #  */
openSUSE Build Service is sponsored by