#
################################################################################
-# use_device(domain, device)
+# use_device_iommu(domain, device)
# Allow a device to be used by a domain
-define(`use_device', `
+# only if an IOMMU provides isolation.
+define(`use_device_iommu', `
allow $1 $1_self:mmu exchange;
- allow $1 $2:resource use;
+ allow $1 $2:resource use_iommu;
+ allow $1 domio_t:mmu { map_read map_write };
+')
+
+# use_device_iommu_nointremap(domain, device)
+# Allow a device to be used by a domain
+# only if an IOMMU is active, even if it does not support
+# interrupt remapping.
+# Allows acceptance of (typically older) less isolating hardware.
+define(`use_device_iommu_nointremap', `
+ allow $1 $1_self:mmu exchange;
+ allow $1 $2:resource { use_iommu use_iommu_nointremap };
+ allow $1 domio_t:mmu { map_read map_write };
+')
+
+# use_device_noiommu(domain, device)
+# Allow a device to be used by a domain
+# even without an IOMMU available.
+define(`use_device_noiommu', `
+ allow $1 $1_self:mmu exchange;
+ allow $1 $2:resource { use_iommu use_iommu_nointremap use_noiommu };
allow $1 domio_t:mmu { map_read map_write };
')
define(`admin_device', `
allow $1 $2:resource { setup stat_device add_device add_irq add_iomem add_ioport remove_device remove_irq remove_iomem remove_ioport plug unplug };
allow $1 $2:hvm bind_irq;
- use_device($1, $2)
+ use_device_noiommu($1, $2)
')
# delegate_devices(priv-domain, target-domain)
#include <xen/errno.h>
#include <xen/guest_access.h>
#include <xen/xenoprof.h>
+#include <xen/iommu.h>
#ifdef CONFIG_HAS_PCI
#include <asm/msi.h>
#endif
#endif
}
+static u32 flask_iommu_resource_use_perm(void)
+{
+ /* Obtain the permission level required for allowing a domain
+ * to use an assigned device.
+ *
+ * An active IOMMU with interrupt remapping capability is essential
+ * for ensuring strict isolation of devices, so provide a distinct
+ * permission for that case and also enable optional support for
+ * less capable hardware (no IOMMU or IOMMU missing intremap capability)
+ * via other separate permissions.
+ */
+ u32 perm = RESOURCE__USE_NOIOMMU;
+
+ if (iommu_enabled)
+ perm = ( iommu_intremap ? RESOURCE__USE_IOMMU :
+ RESOURCE__USE_IOMMU_NOINTREMAP );
+ return perm;
+}
+
static int flask_map_domain_irq (struct domain *d, int irq, void *data)
{
u32 sid, dsid;
int rc = -EPERM;
struct avc_audit_data ad;
+ u32 dperm = flask_iommu_resource_use_perm();
if ( irq >= nr_static_irqs && data ) {
rc = flask_map_domain_msi(d, irq, data, &sid, &ad);
if ( rc )
return rc;
- rc = avc_has_perm(dsid, sid, SECCLASS_RESOURCE, RESOURCE__USE, &ad);
+ rc = avc_has_perm(dsid, sid, SECCLASS_RESOURCE, dperm, &ad);
return rc;
}
int rc = -EPERM;
int irq;
struct avc_audit_data ad;
+ u32 dperm = flask_iommu_resource_use_perm();
rc = current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__ADD);
if ( rc )
return rc;
dsid = domain_sid(d);
- return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, RESOURCE__USE, &ad);
+ return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, dperm, &ad);
}
static int flask_unbind_pt_irq (struct domain *d, struct xen_domctl_bind_pt_irq *bind)
u32 ssid;
u32 dsid;
u32 perm;
+ u32 use_perm;
};
static int _iomem_has_perm(void *v, u32 sid, unsigned long start, unsigned long end)
if ( rc )
return rc;
- return avc_has_perm(data->dsid, sid, SECCLASS_RESOURCE, RESOURCE__USE, &ad);
+ return avc_has_perm(data->dsid, sid, SECCLASS_RESOURCE, data->use_perm, &ad);
}
static int flask_iomem_permission(struct domain *d, uint64_t start, uint64_t end, uint8_t access)
data.ssid = domain_sid(current->domain);
data.dsid = domain_sid(d);
+ data.use_perm = flask_iommu_resource_use_perm();
return security_iterate_iomem_sids(start, end, _iomem_has_perm, &data);
}
u32 dsid, rsid;
int rc = -EPERM;
struct avc_audit_data ad;
- u32 perm = RESOURCE__USE;
+ u32 perm;
rc = security_device_sid(machine_bdf, &rsid);
if ( rc )
/* Writes to the BARs count as setup */
if ( access && (end >= 0x10 && start < 0x28) )
perm = RESOURCE__SETUP;
+ else
+ perm = flask_iommu_resource_use_perm();
AVC_AUDIT_DATA_INIT(&ad, DEV);
ad.device = (unsigned long) machine_bdf;
u32 dsid, rsid;
int rc = -EPERM;
struct avc_audit_data ad;
+ u32 dperm = flask_iommu_resource_use_perm();
rc = current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__ADD);
if ( rc )
return rc;
dsid = domain_sid(d);
- return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, RESOURCE__USE, &ad);
+ return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, dperm, &ad);
}
static int flask_deassign_device(struct domain *d, uint32_t machine_bdf)
u32 dsid, rsid;
int rc = -EPERM;
struct avc_audit_data ad;
+ u32 dperm = flask_iommu_resource_use_perm();
rc = current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__ADD);
if ( rc )
return rc;
dsid = domain_sid(d);
- return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, RESOURCE__USE, &ad);
+ return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, dperm, &ad);
}
static int flask_deassign_dtdevice(struct domain *d, const char *dtpath)
u32 ssid;
u32 dsid;
u32 perm;
+ u32 use_perm;
};
static int _ioport_has_perm(void *v, u32 sid, unsigned long start, unsigned long end)
if ( rc )
return rc;
- return avc_has_perm(data->dsid, sid, SECCLASS_RESOURCE, RESOURCE__USE, &ad);
+ return avc_has_perm(data->dsid, sid, SECCLASS_RESOURCE, data->use_perm, &ad);
}
static int flask_ioport_permission(struct domain *d, uint32_t start, uint32_t end, uint8_t access)
data.ssid = domain_sid(current->domain);
data.dsid = domain_sid(d);
+ data.use_perm = flask_iommu_resource_use_perm();
return security_iterate_ioport_sids(start, end, _ioport_has_perm, &data);
}
# source = domain making the hypercall
# target = domain which will no longer have access to the resource
remove
+# checked when using some core Xen devices (target xen_t)
+# source = domain which will have access to the resource
+# target = xen_t
+ use
# checked when adding a resource to a domain:
# source = domain which will have access to the resource
# target = resource's security label
-# also checked when using some core Xen devices (target xen_t)
- use
+# Requires an active IOMMU capable of interrupt remapping in order to
+# enforce isolation.
+ use_iommu
+# checked when adding a resource to a domain when an IOMMU is available
+# but it is not capable of interrupt mapping:
+# source = domain which will have access to the resource
+# target = resource's security label
+# Enable this to allow some less secure systems to still work.
+ use_iommu_nointremap
+# checked when adding a resource to a domain when no IOMMU present:
+# source = domain which will have access to the resource
+# target = resource's security label
+# Enable this to allow resource use without an active IOMMU.
+ use_noiommu
# PHYSDEVOP_map_pirq and ioapic writes for dom0, when acting on real IRQs
# For GSI interrupts, the IRQ's label is indexed by the IRQ number
# For MSI interrupts, the label of the PCI device is used