domctl/XSM: drop {,de}assign_{,dt}device hooks

Integrate the checking with xsm_domctl(). As a positive side effect,
permissions are then checked at the same early point with and without
Flask. As the DT device path needs fetching earlier (but must not be
double fetched), cache it in a private field of the public interface
struct.

This is part of XSA-492.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
(cherry picked from commit eab54f074f)
This commit is contained in:
Jan Beulich authored and Andrew Cooper committed 2026-06-04 21:47:50 +01:00
1 parent 4618e73b25
commit 923d69856a
8 files changed
+89 -121

No files matched your search

+9
View File
@@ -330,6 +330,10 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
case XEN_DOMCTL_deassign_device:
if ( op->domain == DOMID_IO )
{
#ifdef CONFIG_HAS_DEVICE_TREE
if ( op->u.assign_device.dev == XEN_DOMCTL_DEV_DT )
op->u.assign_device.u.dt.dev = NULL;
#endif
d = dom_io;
break;
}
@@ -337,6 +341,11 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
return -ESRCH;
fallthrough;
case XEN_DOMCTL_test_assign_device:
#ifdef CONFIG_HAS_DEVICE_TREE
if ( op->u.assign_device.dev == XEN_DOMCTL_DEV_DT )
op->u.assign_device.u.dt.dev = NULL;
fallthrough;
#endif
case XEN_DOMCTL_vm_event_op:
if ( op->domain == DOMID_INVALID )
{
+18 -18
View File
@@ -279,15 +279,15 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
if ( (d && d->is_dying) || domctl->u.assign_device.flags )
break;
ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path,
domctl->u.assign_device.u.dt.size,
&dev);
if ( ret )
break;
ret = xsm_assign_dtdevice(XSM_HOOK, d, dt_node_full_name(dev));
if ( ret )
break;
dev = domctl->u.assign_device.u.dt.dev;
if ( !dev )
{
ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path,
domctl->u.assign_device.u.dt.size,
&dev);
if ( ret )
break;
}
if ( domctl->cmd == XEN_DOMCTL_test_assign_device )
{
@@ -335,15 +335,15 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
if ( domctl->u.assign_device.flags )
break;
ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path,
domctl->u.assign_device.u.dt.size,
&dev);
if ( ret )
break;
ret = xsm_deassign_dtdevice(XSM_HOOK, d, dt_node_full_name(dev));
if ( ret )
break;
dev = domctl->u.assign_device.u.dt.dev;
if ( !dev )
{
ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path,
domctl->u.assign_device.u.dt.size,
&dev);
if ( ret )
break;
}
if ( d == dom_io )
{
-8
View File
@@ -1760,10 +1760,6 @@ int iommu_do_pci_domctl(
machine_sbdf = domctl->u.assign_device.u.pci.machine_sbdf;
ret = xsm_assign_device(XSM_HOOK, d, machine_sbdf);
if ( ret )
break;
seg = machine_sbdf >> 16;
bus = PCI_BUS(machine_sbdf);
devfn = PCI_DEVFN(machine_sbdf);
@@ -1805,10 +1801,6 @@ int iommu_do_pci_domctl(
machine_sbdf = domctl->u.assign_device.u.pci.machine_sbdf;
ret = xsm_deassign_device(XSM_HOOK, d, machine_sbdf);
if ( ret )
break;
seg = machine_sbdf >> 16;
bus = PCI_BUS(machine_sbdf);
devfn = PCI_DEVFN(machine_sbdf);
+4 -1
View File
@@ -549,7 +549,10 @@ struct xen_domctl_assign_device {
} pci;
struct {
uint32_t size; /* Length of the path */
XEN_GUEST_HANDLE_64(char) path; /* path to the device tree node */
XEN_GUEST_HANDLE_64(char) path; /* Path to the device tree node */
#ifdef __XEN__
struct dt_device_node *dev; /* Resolved device node of the above */
#endif
} dt;
} u;
};
-32
View File
@@ -403,40 +403,8 @@ static XSM_INLINE int cf_check xsm_get_device_group(
XSM_ASSERT_ACTION(XSM_PRIV);
return xsm_default_action(action, current->domain, NULL);
}
static XSM_INLINE int cf_check xsm_assign_device(
XSM_DEFAULT_ARG struct domain *d, uint32_t machine_bdf)
{
XSM_ASSERT_ACTION(XSM_HOOK);
return xsm_default_action(action, current->domain, d);
}
static XSM_INLINE int cf_check xsm_deassign_device(
XSM_DEFAULT_ARG struct domain *d, uint32_t machine_bdf)
{
XSM_ASSERT_ACTION(XSM_HOOK);
return xsm_default_action(action, current->domain, d);
}
#endif /* HAS_PASSTHROUGH && HAS_PCI */
#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE)
static XSM_INLINE int cf_check 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 cf_check 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 cf_check xsm_resource_plug_core(XSM_DEFAULT_VOID)
{
XSM_ASSERT_ACTION(XSM_HOOK);
-34
View File
@@ -123,13 +123,6 @@ struct xsm_ops {
#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_PCI)
int (*get_device_group)(uint32_t machine_bdf);
int (*assign_device)(struct domain *d, uint32_t machine_bdf);
int (*deassign_device)(struct domain *d, uint32_t machine_bdf);
#endif
#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE)
int (*assign_dtdevice)(struct domain *d, const char *dtpath);
int (*deassign_dtdevice)(struct domain *d, const char *dtpath);
#endif
int (*resource_plug_core)(void);
@@ -514,35 +507,8 @@ static inline int xsm_get_device_group(xsm_default_t def, uint32_t machine_bdf)
{
return alternative_call(xsm_ops.get_device_group, machine_bdf);
}
static inline int xsm_assign_device(
xsm_default_t def, struct domain *d, uint32_t machine_bdf)
{
return alternative_call(xsm_ops.assign_device, d, machine_bdf);
}
static inline int xsm_deassign_device(
xsm_default_t def, struct domain *d, uint32_t machine_bdf)
{
return alternative_call(xsm_ops.deassign_device, d, machine_bdf);
}
#endif /* HAS_PASSTHROUGH && HAS_PCI) */
#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE)
static inline int xsm_assign_dtdevice(
xsm_default_t def, struct domain *d, const char *dtpath)
{
return alternative_call(xsm_ops.assign_dtdevice, d, dtpath);
}
static inline int xsm_deassign_dtdevice(
xsm_default_t def, struct domain *d, const char *dtpath)
{
return alternative_call(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 alternative_call(xsm_ops.resource_plug_pci, machine_bdf);
-7
View File
@@ -77,13 +77,6 @@ static const struct xsm_ops __initconst_cf_clobber dummy_ops = {
#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_PCI)
.get_device_group = xsm_get_device_group,
.assign_device = xsm_assign_device,
.deassign_device = xsm_deassign_device,
#endif
#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE)
.assign_dtdevice = xsm_assign_dtdevice,
.deassign_dtdevice = xsm_deassign_dtdevice,
#endif
.resource_plug_core = xsm_resource_plug_core,
+58 -21
View File
@@ -45,6 +45,17 @@ static int flask_shadow_control(struct domain *d, unsigned int op);
#define pv_shim false
#endif
#ifdef CONFIG_HAS_PASSTHROUGH
#ifdef CONFIG_HAS_PCI
static int flask_assign_device(struct domain *d, unsigned int machine_bdf);
static int flask_deassign_device(struct domain *d, unsigned int machine_bdf);
#endif
#ifdef CONFIG_HAS_DEVICE_TREE
static int flask_assign_dtdevice(struct domain *d, const char *dtpath);
static int flask_deassign_dtdevice(struct domain *d, const char *dtpath);
#endif
#endif /* CONFIG_HAS_PASSTHROUGH */
static uint32_t domain_sid(const struct domain *dom)
{
struct domain_security_struct *dsec = dom->ssid;
@@ -694,16 +705,6 @@ static int cf_check flask_domctl(struct domain *d, struct xen_domctl *op)
/* These have individual XSM hooks (common/domctl.c) */
case XEN_DOMCTL_set_target:
#ifdef CONFIG_HAS_PASSTHROUGH
/*
* These have individual XSM hooks
* (drivers/passthrough/{pci,device_tree.c)
*/
case XEN_DOMCTL_test_assign_device:
case XEN_DOMCTL_assign_device:
case XEN_DOMCTL_deassign_device:
#endif
return 0;
case XEN_DOMCTL_destroydomain:
@@ -783,6 +784,49 @@ static int cf_check flask_domctl(struct domain *d, struct xen_domctl *op)
return flask_shadow_control(d, op->u.shadow_op.op);
#endif
#ifdef CONFIG_HAS_PASSTHROUGH
case XEN_DOMCTL_test_assign_device:
case XEN_DOMCTL_assign_device:
case XEN_DOMCTL_deassign_device:
switch ( op->u.assign_device.dev )
{
#ifdef CONFIG_HAS_PCI
case XEN_DOMCTL_DEV_PCI:
return op->cmd != XEN_DOMCTL_deassign_device
? flask_assign_device(
d, op->u.assign_device.u.pci.machine_sbdf)
: flask_deassign_device(
d, op->u.assign_device.u.pci.machine_sbdf);
#endif
#ifdef CONFIG_HAS_DEVICE_TREE
case XEN_DOMCTL_DEV_DT:
{
struct dt_device_node *dev;
int ret = dt_find_node_by_gpath(op->u.assign_device.u.dt.path,
op->u.assign_device.u.dt.size,
&dev);
if ( ret )
return ret;
op->u.assign_device.u.dt.dev = dev;
return op->cmd != XEN_DOMCTL_deassign_device
? flask_assign_dtdevice(d, dt_node_full_name(dev))
: flask_deassign_dtdevice(d, dt_node_full_name(dev));
}
#endif
default:
/* Unknown type. */
break;
}
return avc_unknown_permission("assign_device", op->cmd);
#endif /* CONFIG_HAS_PASSTHROUGH */
case XEN_DOMCTL_mem_sharing_op:
return current_has_perm(d, SECCLASS_HVM, HVM__MEM_SHARING);
@@ -1400,7 +1444,7 @@ static int flask_test_assign_device(uint32_t machine_bdf)
return avc_current_has_perm(rsid, SECCLASS_RESOURCE, RESOURCE__STAT_DEVICE, NULL);
}
static int cf_check flask_assign_device(struct domain *d, uint32_t machine_bdf)
static int flask_assign_device(struct domain *d, uint32_t machine_bdf)
{
uint32_t dsid, rsid;
int rc = -EPERM;
@@ -1430,7 +1474,7 @@ static int cf_check flask_assign_device(struct domain *d, uint32_t machine_bdf)
return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, dperm, &ad);
}
static int cf_check flask_deassign_device(
static int flask_deassign_device(
struct domain *d, uint32_t machine_bdf)
{
uint32_t rsid;
@@ -1462,7 +1506,7 @@ static int flask_test_assign_dtdevice(const char *dtpath)
NULL);
}
static int cf_check flask_assign_dtdevice(struct domain *d, const char *dtpath)
static int flask_assign_dtdevice(struct domain *d, const char *dtpath)
{
uint32_t dsid, rsid;
int rc = -EPERM;
@@ -1492,7 +1536,7 @@ static int cf_check flask_assign_dtdevice(struct domain *d, const char *dtpath)
return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, dperm, &ad);
}
static int cf_check flask_deassign_dtdevice(
static int flask_deassign_dtdevice(
struct domain *d, const char *dtpath)
{
uint32_t rsid;
@@ -1958,13 +2002,6 @@ static const struct xsm_ops __initconst_cf_clobber flask_ops = {
#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_PCI)
.get_device_group = flask_get_device_group,
.assign_device = flask_assign_device,
.deassign_device = flask_deassign_device,
#endif
#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE)
.assign_dtdevice = flask_assign_dtdevice,
.deassign_dtdevice = flask_deassign_dtdevice,
#endif
.platform_op = flask_platform_op,
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.