]> xenbits.xensource.com Git - people/dariof/xen.git/commitdiff
x86/vMSI: avoid speculative out of bounds accesses
authorJan Beulich <jbeulich@suse.com>
Thu, 4 Jul 2019 14:06:27 +0000 (16:06 +0200)
committerJan Beulich <jbeulich@suse.com>
Thu, 4 Jul 2019 14:06:27 +0000 (16:06 +0200)
Array indexes used in the MMIO read/write emulation functions are
derived from guest controlled values. Restrict their ranges to limit the
side effects of speculative execution.

Note that the index into .msi_ad[] may also be speculatively out of
bounds, by exactly one (indexes 0...3 are possible while the array has
just 3 elements). This is not a problem with the current data layout, as
such overrun of the array would either touch the next element of the
parent array or (for the last entry of the parent array) access the
subsequent acc_valid bit array.

This is part of the speculative hardening effort.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
xen/arch/x86/hvm/vmsi.c

index aeb5a70104d1ed160b4169bffe8e4d80f1a8b800..6597d9f71912abec5a5fb71295db9acb3403bc7d 100644 (file)
@@ -29,6 +29,7 @@
 #include <xen/xmalloc.h>
 #include <xen/lib.h>
 #include <xen/errno.h>
+#include <xen/nospec.h>
 #include <xen/sched.h>
 #include <xen/softirq.h>
 #include <xen/irq.h>
@@ -231,8 +232,10 @@ static int msixtbl_read(const struct hvm_io_handler *handler,
     {
         nr_entry = (address - entry->gtable) / PCI_MSIX_ENTRY_SIZE;
         index = offset / sizeof(uint32_t);
-        if ( nr_entry >= MAX_MSIX_ACC_ENTRIES ||
-             !acc_bit(test, entry, nr_entry, index) )
+        if ( nr_entry >= ARRAY_SIZE(entry->gentries) )
+            goto out;
+        nr_entry = array_index_nospec(nr_entry, ARRAY_SIZE(entry->gentries));
+        if ( !acc_bit(test, entry, nr_entry, index) )
             goto out;
         *pval = entry->gentries[nr_entry].msi_ad[index];
         if ( len == 8 )
@@ -284,14 +287,18 @@ static int msixtbl_write(struct vcpu *v, unsigned long address,
     entry = msixtbl_find_entry(v, address);
     if ( !entry )
         goto out;
-    nr_entry = (address - entry->gtable) / PCI_MSIX_ENTRY_SIZE;
+    nr_entry = array_index_nospec(((address - entry->gtable) /
+                                   PCI_MSIX_ENTRY_SIZE),
+                                  MAX_MSIX_TABLE_ENTRIES);
 
     offset = address & (PCI_MSIX_ENTRY_SIZE - 1);
     if ( offset != PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET )
     {
         index = offset / sizeof(uint32_t);
-        if ( nr_entry < MAX_MSIX_ACC_ENTRIES ) 
+        if ( nr_entry < ARRAY_SIZE(entry->gentries) )
         {
+            nr_entry = array_index_nospec(nr_entry,
+                                          ARRAY_SIZE(entry->gentries));
             entry->gentries[nr_entry].msi_ad[index] = val;
             acc_bit(set, entry, nr_entry, index);
             if ( len == 8 && !index )