@@ -350,6 +350,29 @@ static XSM_INLINE int xsm_deassign_device(XSM_DEFAULT_ARG struct domain *d, uint
#endif /* HAS_PASSTHROUGH && HAS_PCI */
+#if defined(HAS_PASSTHROUGH) && defined(HAS_DEVICE_TREE)
+static XSM_INLINE int xsm_test_assign_dtdevice(XSM_DEFAULT_ARG const char *dtpath)
+{
+ XSM_ASSERT_ACTION(XSM_HOOK);
+ return xsm_default_action(action, current->domain, NULL);
+}
+
+static XSM_INLINE int xsm_assign_dtdevice(XSM_DEFAULT_ARG struct domain *d,
+ const char *dtpath)
+{
+ XSM_ASSERT_ACTION(XSM_HOOK);
+ return xsm_default_action(action, current->domain, d);
+}
+
+static XSM_INLINE int xsm_deassign_dtdevice(XSM_DEFAULT_ARG struct domain *d,
+ const char *dtpath)
+{
+ XSM_ASSERT_ACTION(XSM_HOOK);
+ return xsm_default_action(action, current->domain, d);
+}
+
+#endif /* HAS_PASSTHROUGH && HAS_DEVICE_TREE */
+
static XSM_INLINE int xsm_resource_plug_core(XSM_DEFAULT_VOID)
{
XSM_ASSERT_ACTION(XSM_HOOK);
@@ -121,6 +121,12 @@ struct xsm_operations {
int (*deassign_device) (struct domain *d, uint32_t machine_bdf);
#endif
+#if defined(HAS_PASSTHROUGH) && defined(HAS_DEVICE_TREE)
+ int (*test_assign_dtdevice) (const char *dtpath);
+ int (*assign_dtdevice) (struct domain *d, const char *dtpath);
+ int (*deassign_dtdevice) (struct domain *d, const char *dtpath);
+#endif
+
int (*resource_plug_core) (void);
int (*resource_unplug_core) (void);
int (*resource_plug_pci) (uint32_t machine_bdf);
@@ -473,6 +479,27 @@ static inline int xsm_deassign_device(xsm_default_t def, struct domain *d, uint3
}
#endif /* HAS_PASSTHROUGH && HAS_PCI) */
+#if defined(HAS_PASSTHROUGH) && defined(HAS_DEVICE_TREE)
+static inline int xsm_assign_dtdevice(xsm_default_t def, struct domain *d,
+ const char *dtpath)
+{
+ return xsm_ops->assign_dtdevice(d, dtpath);
+}
+
+static inline int xsm_test_assign_dtdevice(xsm_default_t def,
+ const char *dtpath)
+{
+ return xsm_ops->test_assign_dtdevice(dtpath);
+}
+
+static inline int xsm_deassign_dtdevice(xsm_default_t def, struct domain *d,
+ const char *dtpath)
+{
+ return xsm_ops->deassign_dtdevice(d, dtpath);
+}
+
+#endif /* HAS_PASSTHROUGH && HAS_DEVICE_TREE */
+
static inline int xsm_resource_plug_pci (xsm_default_t def, uint32_t machine_bdf)
{
return xsm_ops->resource_plug_pci(machine_bdf);
@@ -96,6 +96,12 @@ void xsm_fixup_ops (struct xsm_operations *ops)
set_to_dummy_if_null(ops, deassign_device);
#endif
+#if defined(HAS_PASSTHROUGH) && defined(HAS_DEVICE_TREE)
+ set_to_dummy_if_null(ops, test_assign_dtdevice);
+ set_to_dummy_if_null(ops, assign_dtdevice);
+ set_to_dummy_if_null(ops, deassign_dtdevice);
+#endif
+
set_to_dummy_if_null(ops, resource_plug_core);
set_to_dummy_if_null(ops, resource_unplug_core);
set_to_dummy_if_null(ops, resource_plug_pci);
@@ -600,6 +600,9 @@ void avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
case AVC_AUDIT_DATA_MEMORY:
avc_printk(&buf, "pte=%#lx mfn=%#lx ", a->memory.pte, a->memory.mfn);
break;
+ case AVC_AUDIT_DATA_DTDEV:
+ avc_printk(&buf, "dtdevice=%s ", a->dtdev);
+ break;
}
avc_dump_query(&buf, ssid, tsid, tclass);
@@ -589,7 +589,12 @@ static int flask_domctl(struct domain *d, int cmd)
case XEN_DOMCTL_shadow_op:
case XEN_DOMCTL_ioport_permission:
case XEN_DOMCTL_ioport_mapping:
- /* These have individual XSM hooks (drivers/passthrough/iommu.c) */
+#endif
+#ifdef HAS_PASSTHROUGH
+ /*
+ * These have individual XSM hooks
+ * (drivers/passthrough/{pci,device_tree.c)
+ */
case XEN_DOMCTL_get_device_group:
case XEN_DOMCTL_test_assign_device:
case XEN_DOMCTL_assign_device:
@@ -1231,6 +1236,62 @@ static int flask_deassign_device(struct domain *d, uint32_t machine_bdf)
}
#endif /* HAS_PASSTHROUGH && HAS_PCI */
+#if defined(HAS_PASSTHROUGH) && defined(HAS_DEVICE_TREE)
+static int flask_test_assign_dtdevice(const char *dtpath)
+{
+ u32 rsid;
+ int rc = -EPERM;
+
+ rc = security_devicetree_sid(dtpath, &rsid);
+ if ( rc )
+ return rc;
+
+ return avc_current_has_perm(rsid, SECCLASS_RESOURCE, RESOURCE__STAT_DEVICE,
+ NULL);
+}
+
+static int flask_assign_dtdevice(struct domain *d, const char *dtpath)
+{
+ u32 dsid, rsid;
+ int rc = -EPERM;
+ struct avc_audit_data ad;
+
+ rc = current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__ADD);
+ if ( rc )
+ return rc;
+
+ rc = security_devicetree_sid(dtpath, &rsid);
+ if ( rc )
+ return rc;
+
+ AVC_AUDIT_DATA_INIT(&ad, DTDEV);
+ ad.dtdev = dtpath;
+ rc = avc_current_has_perm(rsid, SECCLASS_RESOURCE, RESOURCE__ADD_DEVICE, &ad);
+ if ( rc )
+ return rc;
+
+ dsid = domain_sid(d);
+ return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, RESOURCE__USE, &ad);
+}
+
+static int flask_deassign_dtdevice(struct domain *d, const char *dtpath)
+{
+ u32 rsid;
+ int rc = -EPERM;
+
+ rc = current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__REMOVE);
+ if ( rc )
+ return rc;
+
+ rc = security_devicetree_sid(dtpath, &rsid);
+ if ( rc )
+ return rc;
+
+ return avc_current_has_perm(rsid, SECCLASS_RESOURCE, RESOURCE__REMOVE_DEVICE,
+ NULL);
+}
+#endif /* HAS_PASSTHROUGH && HAS_DEVICE_TREE */
+
#ifdef HAS_MEM_ACCESS
static int flask_vm_event_control(struct domain *d, int mode, int op)
{
@@ -1598,6 +1659,12 @@ static struct xsm_operations flask_ops = {
.deassign_device = flask_deassign_device,
#endif
+#if defined(HAS_PASSTHROUGH) && defined(HAS_DEVICE_TREE)
+ .test_assign_dtdevice = flask_test_assign_dtdevice,
+ .assign_dtdevice = flask_assign_dtdevice,
+ .deassign_dtdevice = flask_deassign_dtdevice,
+#endif
+
#ifdef HAS_MEM_ACCESS
.vm_event_control = flask_vm_event_control,
.vm_event_op = flask_vm_event_op,
@@ -39,6 +39,7 @@ struct avc_audit_data {
#define AVC_AUDIT_DATA_IRQ 2
#define AVC_AUDIT_DATA_RANGE 3
#define AVC_AUDIT_DATA_MEMORY 4
+#define AVC_AUDIT_DATA_DTDEV 5
struct domain *sdom;
struct domain *tdom;
union {
@@ -52,6 +53,7 @@ struct avc_audit_data {
unsigned long pte;
unsigned long mfn;
} memory;
+ const char *dtdev;
};
};
@@ -416,7 +416,7 @@ class resource
remove_iomem
# XEN_DOMCTL_get_device_group, XEN_DOMCTL_test_assign_device:
# source = domain making the hypercall
-# target = PCI device being queried
+# target = device being queried
stat_device
# XEN_DOMCTL_assign_device
add_device