[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 4/4] x86/vLAPIC: avoid speculative out of bounds accesses



Array indexes used in the MMIO and MSR read/write emulation functions
are derived from guest controlled values. Restrict their ranges to limit
the side effects of speculative execution.

Remove the unused vlapic_lvt_{vector,dm}() instead of adjusting them.

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>

--- a/xen/arch/x86/hvm/vlapic.c
+++ b/xen/arch/x86/hvm/vlapic.c
@@ -23,6 +23,7 @@
 #include <xen/domain.h>
 #include <xen/domain_page.h>
 #include <xen/event.h>
+#include <xen/nospec.h>
 #include <xen/trace.h>
 #include <xen/lib.h>
 #include <xen/sched.h>
@@ -44,6 +45,8 @@
 #define VLAPIC_VERSION                  0x00050014
 #define VLAPIC_LVT_NUM                  6
 
+#define VLAPIC_OFFSET_MASK(vlapic) ((ARRAY_SIZE((vlapic)->regs->data) - 1) & 
~0xf)
+
 #define LVT_MASK \
     (APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK)
 
@@ -65,12 +68,6 @@ static const unsigned int vlapic_lvt_mas
      LVT_MASK
 };
 
-#define vlapic_lvt_vector(vlapic, lvt_type)                     \
-    (vlapic_get_reg(vlapic, lvt_type) & APIC_VECTOR_MASK)
-
-#define vlapic_lvt_dm(vlapic, lvt_type)                         \
-    (vlapic_get_reg(vlapic, lvt_type) & APIC_MODE_MASK)
-
 #define vlapic_lvtt_period(vlapic)                              \
     ((vlapic_get_reg(vlapic, APIC_LVTT) & APIC_TIMER_MODE_MASK) \
      == APIC_TIMER_MODE_PERIODIC)
@@ -632,7 +629,8 @@ static int vlapic_mmio_read(struct vcpu
      */
     if ( (alignment + len) <= 4 && offset <= (APIC_TDCR + 3) )
     {
-        uint32_t reg = vlapic_read_aligned(vlapic, offset & ~0xf);
+        uint32_t reg = vlapic_read_aligned(vlapic,
+                                           offset & 
VLAPIC_OFFSET_MASK(vlapic));
 
         switch ( len )
         {
@@ -665,7 +663,7 @@ int guest_rdmsr_x2apic(const struct vcpu
     };
     const struct vlapic *vlapic = vcpu_vlapic(v);
     uint64_t high = 0;
-    uint32_t reg = msr - MSR_X2APIC_FIRST, offset = reg << 4;
+    uint32_t reg = msr - MSR_X2APIC_FIRST, offset;
 
     /*
      * The read side looks as if it might be safe to use outside of current
@@ -675,9 +673,14 @@ int guest_rdmsr_x2apic(const struct vcpu
     ASSERT(v == current);
 
     if ( !vlapic_x2apic_mode(vlapic) ||
-         (reg >= sizeof(readable) * 8) || !test_bit(reg, readable) )
+         (reg >= sizeof(readable) * 8) )
         return X86EMUL_EXCEPTION;
 
+    reg = array_index_nospec(reg, sizeof(readable) * 8);
+    if ( !test_bit(reg, readable) )
+        return X86EMUL_EXCEPTION;
+
+    offset = reg << 4;
     if ( offset == APIC_ICR )
         high = (uint64_t)vlapic_read_aligned(vlapic, APIC_ICR2) << 32;
 
@@ -856,8 +859,8 @@ void vlapic_reg_write(struct vcpu *v, un
     case APIC_LVTERR:       /* LVT Error Reg */
         if ( vlapic_sw_disabled(vlapic) )
             val |= APIC_LVT_MASKED;
-        val &= vlapic_lvt_mask[(reg - APIC_LVTT) >> 4];
-        vlapic_set_reg(vlapic, reg, val);
+        val &= array_access_nospec(vlapic_lvt_mask, (reg - APIC_LVTT) >> 4);
+        vlapic_set_reg(vlapic, reg & VLAPIC_OFFSET_MASK(vlapic), val);
         if ( reg == APIC_LVT0 )
         {
             vlapic_adjust_i8259_target(v->domain);
@@ -901,8 +904,6 @@ static int vlapic_mmio_write(struct vcpu
     unsigned int offset = address - vlapic_base_address(vlapic);
     unsigned int alignment = offset & 0xf;
 
-    offset &= ~0xf;
-
     if ( offset != APIC_EOI )
         HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
                     "offset %#x with length %#x, and value is %#lx",
@@ -915,8 +916,10 @@ static int vlapic_mmio_write(struct vcpu
      * Some processors support smaller accesses, so we allow any access which
      * fully fits within the 32-bit register.
      */
-    if ( (alignment + len) <= 4 && offset <= APIC_TDCR )
+    if ( (alignment + len) <= 4 && offset <= APIC_TDCR + 3 )
     {
+        offset &= VLAPIC_OFFSET_MASK(vlapic);
+
         if ( unlikely(len < 4) )
         {
             uint32_t reg = vlapic_read_aligned(vlapic, offset);
@@ -946,7 +949,7 @@ static int vlapic_mmio_write(struct vcpu
 int vlapic_apicv_write(struct vcpu *v, unsigned int offset)
 {
     struct vlapic *vlapic = vcpu_vlapic(v);
-    uint32_t val = vlapic_get_reg(vlapic, offset);
+    uint32_t val = vlapic_get_reg(vlapic, offset & VLAPIC_OFFSET_MASK(vlapic));
 
     if ( vlapic_x2apic_mode(vlapic) )
     {




_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.