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

[PATCH v6 04/13] vpci: restrict unhandled read/write operations for guests



From: Oleksandr Andrushchenko <oleksandr_andrushchenko@xxxxxxxx>

A guest can read and write those registers which are not emulated and
have no respective vPCI handlers, so it can access the HW directly.
In order to prevent a guest from reads and writes from/to the unhandled
registers make sure only hardware domain can access HW directly and restrict
guests from doing so.

Suggested-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@xxxxxxxx>

---
New in v6
---
 xen/drivers/vpci/vpci.c | 32 +++++++++++++++++++++-----------
 1 file changed, 21 insertions(+), 11 deletions(-)

diff --git a/xen/drivers/vpci/vpci.c b/xen/drivers/vpci/vpci.c
index cb2ababa28e3..f8a93e61c08f 100644
--- a/xen/drivers/vpci/vpci.c
+++ b/xen/drivers/vpci/vpci.c
@@ -215,11 +215,15 @@ int vpci_remove_register(struct vpci *vpci, unsigned int 
offset,
 }
 
 /* Wrappers for performing reads/writes to the underlying hardware. */
-static uint32_t vpci_read_hw(pci_sbdf_t sbdf, unsigned int reg,
+static uint32_t vpci_read_hw(bool is_hwdom, pci_sbdf_t sbdf, unsigned int reg,
                              unsigned int size)
 {
     uint32_t data;
 
+    /* Guest domains are not allowed to read real hardware. */
+    if ( !is_hwdom )
+        return ~(uint32_t)0;
+
     switch ( size )
     {
     case 4:
@@ -260,9 +264,13 @@ static uint32_t vpci_read_hw(pci_sbdf_t sbdf, unsigned int 
reg,
     return data;
 }
 
-static void vpci_write_hw(pci_sbdf_t sbdf, unsigned int reg, unsigned int size,
-                          uint32_t data)
+static void vpci_write_hw(bool is_hwdom, pci_sbdf_t sbdf, unsigned int reg,
+                          unsigned int size, uint32_t data)
 {
+    /* Guest domains are not allowed to write real hardware. */
+    if ( !is_hwdom )
+        return;
+
     switch ( size )
     {
     case 4:
@@ -322,6 +330,7 @@ uint32_t vpci_read(pci_sbdf_t sbdf, unsigned int reg, 
unsigned int size)
     const struct vpci_register *r;
     unsigned int data_offset = 0;
     uint32_t data = ~(uint32_t)0;
+    bool is_hwdom = is_hardware_domain(d);
 
     if ( !size )
     {
@@ -332,13 +341,13 @@ uint32_t vpci_read(pci_sbdf_t sbdf, unsigned int reg, 
unsigned int size)
     /* Find the PCI dev matching the address. */
     pdev = pci_get_pdev_by_domain(d, sbdf.seg, sbdf.bus, sbdf.devfn);
     if ( !pdev )
-        return vpci_read_hw(sbdf, reg, size);
+        return vpci_read_hw(is_hwdom, sbdf, reg, size);
 
     spin_lock(&pdev->vpci_lock);
     if ( !pdev->vpci )
     {
         spin_unlock(&pdev->vpci_lock);
-        return vpci_read_hw(sbdf, reg, size);
+        return vpci_read_hw(is_hwdom, sbdf, reg, size);
     }
 
     /* Read from the hardware or the emulated register handlers. */
@@ -361,7 +370,7 @@ uint32_t vpci_read(pci_sbdf_t sbdf, unsigned int reg, 
unsigned int size)
         {
             /* Heading gap, read partial content from hardware. */
             read_size = r->offset - emu.offset;
-            val = vpci_read_hw(sbdf, emu.offset, read_size);
+            val = vpci_read_hw(is_hwdom, sbdf, emu.offset, read_size);
             data = merge_result(data, val, read_size, data_offset);
             data_offset += read_size;
         }
@@ -387,7 +396,7 @@ uint32_t vpci_read(pci_sbdf_t sbdf, unsigned int reg, 
unsigned int size)
     if ( data_offset < size )
     {
         /* Tailing gap, read the remaining. */
-        uint32_t tmp_data = vpci_read_hw(sbdf, reg + data_offset,
+        uint32_t tmp_data = vpci_read_hw(is_hwdom, sbdf, reg + data_offset,
                                          size - data_offset);
 
         data = merge_result(data, tmp_data, size - data_offset, data_offset);
@@ -430,6 +439,7 @@ void vpci_write(pci_sbdf_t sbdf, unsigned int reg, unsigned 
int size,
     const struct vpci_register *r;
     unsigned int data_offset = 0;
     const unsigned long *ro_map = pci_get_ro_map(sbdf.seg);
+    bool is_hwdom = is_hardware_domain(d);
 
     if ( !size )
     {
@@ -448,7 +458,7 @@ void vpci_write(pci_sbdf_t sbdf, unsigned int reg, unsigned 
int size,
     pdev = pci_get_pdev_by_domain(d, sbdf.seg, sbdf.bus, sbdf.devfn);
     if ( !pdev )
     {
-        vpci_write_hw(sbdf, reg, size, data);
+        vpci_write_hw(is_hwdom, sbdf, reg, size, data);
         return;
     }
 
@@ -456,7 +466,7 @@ void vpci_write(pci_sbdf_t sbdf, unsigned int reg, unsigned 
int size,
     if ( !pdev->vpci )
     {
         spin_unlock(&pdev->vpci_lock);
-        vpci_write_hw(sbdf, reg, size, data);
+        vpci_write_hw(is_hwdom, sbdf, reg, size, data);
         return;
     }
 
@@ -479,7 +489,7 @@ void vpci_write(pci_sbdf_t sbdf, unsigned int reg, unsigned 
int size,
         if ( emu.offset < r->offset )
         {
             /* Heading gap, write partial content to hardware. */
-            vpci_write_hw(sbdf, emu.offset, r->offset - emu.offset,
+            vpci_write_hw(is_hwdom, sbdf, emu.offset, r->offset - emu.offset,
                           data >> (data_offset * 8));
             data_offset += r->offset - emu.offset;
         }
@@ -498,7 +508,7 @@ void vpci_write(pci_sbdf_t sbdf, unsigned int reg, unsigned 
int size,
 
     if ( data_offset < size )
         /* Tailing gap, write the remaining. */
-        vpci_write_hw(sbdf, reg + data_offset, size - data_offset,
+        vpci_write_hw(is_hwdom, sbdf, reg + data_offset, size - data_offset,
                       data >> (data_offset * 8));
 }
 
-- 
2.25.1




 


Rackspace

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