mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
xsm: add checks on PCI configuration access
PCI configuration access is allowed to any privileged domain regardless of I/O port access restrictions; add XSM hooks for these accesses. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
This commit is contained in:
1 parent
f2271ccd45
commit
32103e04be
5 files changed
+73
-4
No files matched your search
+22
-4
@@ -72,6 +72,7 @@
|
||||
#include <asm/mc146818rtc.h>
|
||||
#include <asm/hpet.h>
|
||||
#include <public/arch-x86/cpuid.h>
|
||||
#include <xsm/xsm.h>
|
||||
|
||||
/*
|
||||
* opt_nmi: one of 'ignore', 'dom0', or 'fatal'.
|
||||
@@ -1680,6 +1681,21 @@ static int admin_io_okay(
|
||||
return ioports_access_permitted(v->domain, port, port + bytes - 1);
|
||||
}
|
||||
|
||||
static int pci_cfg_ok(struct domain *d, int write, int size)
|
||||
{
|
||||
uint32_t machine_bdf;
|
||||
uint16_t start, end;
|
||||
if (!IS_PRIV(d))
|
||||
return 0;
|
||||
|
||||
machine_bdf = (d->arch.pci_cf8 >> 8) & 0xFFFF;
|
||||
start = d->arch.pci_cf8 & 0xFF;
|
||||
end = start + size - 1;
|
||||
if (xsm_pci_config_permission(d, machine_bdf, start, end, write))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint32_t guest_io_read(
|
||||
unsigned int port, unsigned int bytes,
|
||||
struct vcpu *v, struct cpu_user_regs *regs)
|
||||
@@ -1726,12 +1742,13 @@ static uint32_t guest_io_read(
|
||||
size = 4;
|
||||
sub_data = v->domain->arch.pci_cf8;
|
||||
}
|
||||
else if ( ((port & 0xfffc) == 0xcfc) && IS_PRIV(v->domain) )
|
||||
else if ( (port & 0xfffc) == 0xcfc )
|
||||
{
|
||||
size = min(bytes, 4 - (port & 3));
|
||||
if ( size == 3 )
|
||||
size = 2;
|
||||
sub_data = pci_conf_read(v->domain->arch.pci_cf8, port & 3, size);
|
||||
if ( pci_cfg_ok(v->domain, 0, size) )
|
||||
sub_data = pci_conf_read(v->domain->arch.pci_cf8, port & 3, size);
|
||||
}
|
||||
|
||||
if ( size == 4 )
|
||||
@@ -1798,12 +1815,13 @@ static void guest_io_write(
|
||||
size = 4;
|
||||
v->domain->arch.pci_cf8 = data;
|
||||
}
|
||||
else if ( ((port & 0xfffc) == 0xcfc) && IS_PRIV(v->domain) )
|
||||
else if ( (port & 0xfffc) == 0xcfc )
|
||||
{
|
||||
size = min(bytes, 4 - (port & 3));
|
||||
if ( size == 3 )
|
||||
size = 2;
|
||||
pci_conf_write(v->domain->arch.pci_cf8, port & 3, size, data);
|
||||
if ( pci_cfg_ok(v->domain, 1, size) )
|
||||
pci_conf_write(v->domain->arch.pci_cf8, port & 3, size, data);
|
||||
}
|
||||
|
||||
if ( size == 4 )
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <xen/xmalloc.h>
|
||||
#include <xen/pci.h>
|
||||
#include <xen/pci_regs.h>
|
||||
#include <xsm/xsm.h>
|
||||
|
||||
#include "mmconfig.h"
|
||||
|
||||
@@ -58,6 +59,7 @@ int pci_mmcfg_read(unsigned int seg, unsigned int bus,
|
||||
unsigned int devfn, int reg, int len, u32 *value)
|
||||
{
|
||||
char __iomem *addr;
|
||||
uint32_t mbdf;
|
||||
|
||||
/* Why do we have this when nobody checks it. How about a BUG()!? -AK */
|
||||
if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) {
|
||||
@@ -65,6 +67,12 @@ err: *value = -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mbdf = (seg << 16) | (bus << 8) | devfn;
|
||||
if (xsm_pci_config_permission(current->domain, mbdf, reg, reg + len - 1, 0)) {
|
||||
*value = -1;
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
addr = pci_dev_base(seg, bus, devfn);
|
||||
if (!addr)
|
||||
goto err;
|
||||
@@ -88,11 +96,16 @@ int pci_mmcfg_write(unsigned int seg, unsigned int bus,
|
||||
unsigned int devfn, int reg, int len, u32 value)
|
||||
{
|
||||
char __iomem *addr;
|
||||
uint32_t mbdf;
|
||||
|
||||
/* Why do we have this when nobody checks it. How about a BUG()!? -AK */
|
||||
if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
|
||||
return -EINVAL;
|
||||
|
||||
mbdf = (seg << 16) | (bus << 8) | devfn;
|
||||
if (xsm_pci_config_permission(current->domain, mbdf, reg, reg + len - 1, 1))
|
||||
return -EPERM;
|
||||
|
||||
addr = pci_dev_base(seg, bus, devfn);
|
||||
if (!addr)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -113,6 +113,7 @@ struct xsm_operations {
|
||||
int (*schedop_shutdown) (struct domain *d1, struct domain *d2);
|
||||
int (*irq_permission) (struct domain *d, int pirq, uint8_t allow);
|
||||
int (*iomem_permission) (struct domain *d, uint64_t s, uint64_t e, uint8_t allow);
|
||||
int (*pci_config_permission) (struct domain *d, uint32_t machine_bdf, uint16_t start, uint16_t end, uint8_t access);
|
||||
|
||||
int (*get_device_group) (uint32_t machine_bdf);
|
||||
int (*test_assign_device) (uint32_t machine_bdf);
|
||||
@@ -473,6 +474,11 @@ static inline int xsm_iomem_permission (struct domain *d, uint64_t s, uint64_t e
|
||||
return xsm_call(iomem_permission(d, s, e, allow));
|
||||
}
|
||||
|
||||
static inline int xsm_pci_config_permission (struct domain *d, uint32_t machine_bdf, uint16_t start, uint16_t end, uint8_t access)
|
||||
{
|
||||
return xsm_call(pci_config_permission(d, machine_bdf, start, end, access));
|
||||
}
|
||||
|
||||
static inline int xsm_get_device_group(uint32_t machine_bdf)
|
||||
{
|
||||
return xsm_call(get_device_group(machine_bdf));
|
||||
|
||||
@@ -369,6 +369,13 @@ static int dummy_iomem_permission (struct domain *d, uint64_t s, uint64_t e, uin
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dummy_pci_config_permission (struct domain *d, uint32_t machine_bdf,
|
||||
uint16_t start, uint16_t end,
|
||||
uint8_t access)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
static int dummy_shadow_control (struct domain *d, uint32_t op)
|
||||
{
|
||||
@@ -631,6 +638,7 @@ void xsm_fixup_ops (struct xsm_operations *ops)
|
||||
|
||||
set_to_dummy_if_null(ops, irq_permission);
|
||||
set_to_dummy_if_null(ops, iomem_permission);
|
||||
set_to_dummy_if_null(ops, pci_config_permission);
|
||||
|
||||
set_to_dummy_if_null(ops, test_assign_device);
|
||||
set_to_dummy_if_null(ops, assign_device);
|
||||
|
||||
@@ -762,6 +762,29 @@ static int flask_iomem_permission(struct domain *d, uint64_t start, uint64_t end
|
||||
return security_iterate_iomem_sids(start, end, _iomem_has_perm, &data);
|
||||
}
|
||||
|
||||
static int flask_pci_config_permission(struct domain *d, uint32_t machine_bdf, uint16_t start, uint16_t end, uint8_t access)
|
||||
{
|
||||
u32 rsid;
|
||||
int rc = -EPERM;
|
||||
struct avc_audit_data ad;
|
||||
struct domain_security_struct *ssec;
|
||||
u32 perm = RESOURCE__USE;
|
||||
|
||||
rc = security_device_sid(machine_bdf, &rsid);
|
||||
if ( rc )
|
||||
return rc;
|
||||
|
||||
/* Writes to the BARs count as setup */
|
||||
if ( access && (end >= 0x10 && start < 0x28) )
|
||||
perm = RESOURCE__SETUP;
|
||||
|
||||
AVC_AUDIT_DATA_INIT(&ad, DEV);
|
||||
ad.device = (unsigned long) machine_bdf;
|
||||
ssec = d->ssid;
|
||||
return avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, &ad);
|
||||
|
||||
}
|
||||
|
||||
static int flask_resource_plug_core(void)
|
||||
{
|
||||
struct domain_security_struct *ssec;
|
||||
@@ -1481,6 +1504,7 @@ static struct xsm_operations flask_ops = {
|
||||
|
||||
.irq_permission = flask_irq_permission,
|
||||
.iomem_permission = flask_iomem_permission,
|
||||
.pci_config_permission = flask_pci_config_permission,
|
||||
|
||||
.resource_plug_core = flask_resource_plug_core,
|
||||
.resource_unplug_core = flask_resource_unplug_core,
|
||||
|
||||