]> xenbits.xensource.com Git - people/liuw/xen.git/commitdiff
x86/hvm/hpet: block speculative out-of-bound accesses
authorNorbert Manthey <nmanthey@amazon.de>
Mon, 28 Jan 2019 16:37:20 +0000 (17:37 +0100)
committerJan Beulich <jbeulich@suse.com>
Mon, 28 Jan 2019 16:37:20 +0000 (17:37 +0100)
When interacting with hpet, read and write operations can be executed
during instruction emulation, where the guest controls the data that
is used. As it is hard to predict the number of instructions that are
executed speculatively, we prevent out-of-bound accesses by using the
array_index_nospec function for guest specified addresses that should
be used for hpet operations.

We introduce another macro that uses the ARRAY_SIZE macro to block
speculative accesses. For arrays that are statically accessed, this macro
can be used instead of the usual macro. Using this macro results in more
readable code, and allows to modify the way this case is handled in a
single place.

This commit is part of the SpectreV1+L1TF mitigation patch series.

Signed-off-by: Norbert Manthey <nmanthey@amazon.de>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Release-acked-by: Juergen Gross <jgross@suse.com>
xen/arch/x86/hvm/hpet.c
xen/include/xen/nospec.h

index be371ecc0b92e69a8eb04eaf8d65a8ef94d21844..a9167581061e7e2b234fad61075648ee2b6a8068 100644 (file)
@@ -25,6 +25,7 @@
 #include <xen/sched.h>
 #include <xen/event.h>
 #include <xen/trace.h>
+#include <xen/nospec.h>
 
 #define domain_vhpet(x) (&(x)->arch.hvm.pl_time->vhpet)
 #define vcpu_vhpet(x)   (domain_vhpet((x)->domain))
@@ -124,15 +125,18 @@ static inline uint64_t hpet_read64(HPETState *h, unsigned long addr,
     case HPET_Tn_CFG(0):
     case HPET_Tn_CFG(1):
     case HPET_Tn_CFG(2):
-        return h->hpet.timers[HPET_TN(CFG, addr)].config;
+        return array_access_nospec(h->hpet.timers, HPET_TN(CFG, addr)).config;
     case HPET_Tn_CMP(0):
     case HPET_Tn_CMP(1):
     case HPET_Tn_CMP(2):
-        return hpet_get_comparator(h, HPET_TN(CMP, addr), guest_time);
+        return hpet_get_comparator(h,
+                                   array_index_nospec(HPET_TN(CMP, addr),
+                                                      ARRAY_SIZE(h->hpet.timers)),
+                                   guest_time);
     case HPET_Tn_ROUTE(0):
     case HPET_Tn_ROUTE(1):
     case HPET_Tn_ROUTE(2):
-        return h->hpet.timers[HPET_TN(ROUTE, addr)].fsb;
+        return array_access_nospec(h->hpet.timers, HPET_TN(ROUTE, addr)).fsb;
     }
 
     return 0;
@@ -438,7 +442,7 @@ static int hpet_write(
     case HPET_Tn_CFG(0):
     case HPET_Tn_CFG(1):
     case HPET_Tn_CFG(2):
-        tn = HPET_TN(CFG, addr);
+        tn = array_index_nospec(HPET_TN(CFG, addr), ARRAY_SIZE(h->hpet.timers));
 
         h->hpet.timers[tn].config =
             hpet_fixup_reg(new_val, old_val,
@@ -480,7 +484,7 @@ static int hpet_write(
     case HPET_Tn_CMP(0):
     case HPET_Tn_CMP(1):
     case HPET_Tn_CMP(2):
-        tn = HPET_TN(CMP, addr);
+        tn = array_index_nospec(HPET_TN(CMP, addr), ARRAY_SIZE(h->hpet.timers));
         if ( timer_is_periodic(h, tn) &&
              !(h->hpet.timers[tn].config & HPET_TN_SETVAL) )
         {
@@ -523,8 +527,7 @@ static int hpet_write(
     case HPET_Tn_ROUTE(0):
     case HPET_Tn_ROUTE(1):
     case HPET_Tn_ROUTE(2):
-        tn = HPET_TN(ROUTE, addr);
-        h->hpet.timers[tn].fsb = new_val;
+        array_access_nospec(h->hpet.timers, HPET_TN(ROUTE, addr)).fsb = new_val;
         break;
 
     default:
index 48793996e8ab6cb9c8fb64d7e45f10414fbc0c9a..8acfa60f1b71461836b81e73d2af4a116cfa6598 100644 (file)
@@ -58,6 +58,12 @@ static inline unsigned long array_index_mask_nospec(unsigned long index,
     (typeof(_i)) (_i & _mask);                                          \
 })
 
+/*
+ * array_access_nospec - allow nospec access for static size arrays
+ */
+#define array_access_nospec(array, index)                               \
+    (array)[array_index_nospec(index, ARRAY_SIZE(array))]
+
 #endif /* XEN_NOSPEC_H */
 
 /*