x86: allow stubdom access to irq created for msi

Stubdomains need to be given sufficient privilege over the guest which it
provides emulation for in order for PCI passthrough to work correctly.
When a HVM domain try to enable MSI, QEMU in stubdomain calls
PHYSDEVOP_map_pirq, but later it needs to call XEN_DOMCTL_bind_pt_irq as
part of xc_domain_update_msi_irq. Give the stubdomain enough permissions
over the mapped interrupt in order to bind it successfully to it's
target domain.

This is not needed for PCI INTx, because IRQ in that case is known
beforehand and the stubdomain is given permissions over this IRQ by
libxl__device_pci_add (there's a do_pci_add against the stubdomain).

create_irq() already grant IRQ access to hardware_domain, with
assumption the device model lives there.
Modify create_irq() to take additional parameter, whether to grant
permissions to the domain creating the IRQ, which may be dom0 or a
stubdomain. Do this instead of granting access always to
hardware_domain. Save ID of the domain given permission, to revoke it in
destroy_irq() - easier and cleaner than replaying logic of create_irq()
parameter. Use domid instead of actual reference to the domain,
because it might get destroyed before destroying IRQ (stubdomain is
destroyed before its target domain). And it is not an issue,
because IRQ permissions live within domain structure, so destroying
a domain also implicitly revoke the permission.  Potential domid
reuse is detected by checking if that domain does have permission
over the IRQ being destroyed.

Then, adjust all callers to provide the parameter. In case of Xen
internal allocations, set it to false, but for domain accessible
interrupt set it to true.

Inspired by https://github.com/OpenXT/xenclient-oe/blob/5e0e7304a5a3c75ef01240a1e3673665b2aaf05e/recipes-extended/xen/files/stubdomain-msi-irq-access.patch by Eric Chanudet <chanudete@ainfosec.com>.

Signed-off-by: Simon Gaiser <simon@invisiblethingslab.com>
Signed-off-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
Simon Gaiser authored and Jan Beulich committed 2019-09-27 15:04:08 +02:00
1 parent fab256ba5f
commit 92d9101eab
6 files changed
+47 -18

No files matched your search

+2 -1
View File
@@ -11,6 +11,7 @@
#include <xen/softirq.h>
#include <xen/irq.h>
#include <xen/numa.h>
#include <xen/sched.h>
#include <asm/fixmap.h>
#include <asm/div64.h>
#include <asm/hpet.h>
@@ -368,7 +369,7 @@ static int __init hpet_assign_irq(struct hpet_event_channel *ch)
{
int irq;
if ( (irq = create_irq(NUMA_NO_NODE)) < 0 )
if ( (irq = create_irq(NUMA_NO_NODE, false)) < 0 )
return irq;
ch->msi.irq = irq;
+31 -13
View File
@@ -254,7 +254,8 @@ void __init clear_irq_vector(int irq)
/*
* Dynamic irq allocate and deallocation for MSI
*/
int create_irq(nodeid_t node)
int create_irq(nodeid_t node, bool grant_access)
{
int irq, ret;
struct irq_desc *desc;
@@ -282,18 +283,25 @@ int create_irq(nodeid_t node)
}
ret = assign_irq_vector(irq, mask);
}
ASSERT(desc->arch.creator_domid == DOMID_INVALID);
if (ret < 0)
{
desc->arch.used = IRQ_UNUSED;
irq = ret;
}
else if ( hardware_domain )
else if ( grant_access )
{
ret = irq_permit_access(hardware_domain, irq);
struct domain *currd = current->domain;
ret = irq_permit_access(currd, irq);
if ( ret )
printk(XENLOG_G_ERR
"Could not grant Dom0 access to IRQ%d (error %d)\n",
irq, ret);
"Could not grant %pd access to IRQ%d (error %d)\n",
currd, irq, ret);
else
desc->arch.creator_domid = currd->domain_id;
}
return irq;
@@ -307,14 +315,23 @@ void destroy_irq(unsigned int irq)
BUG_ON(!MSI_IRQ(irq));
if ( hardware_domain )
if ( desc->arch.creator_domid != DOMID_INVALID )
{
int err = irq_deny_access(hardware_domain, irq);
struct domain *d = get_domain_by_id(desc->arch.creator_domid);
if ( err )
printk(XENLOG_G_ERR
"Could not revoke Dom0 access to IRQ%u (error %d)\n",
irq, err);
if ( d )
{
int err = irq_deny_access(d, irq);
if ( err )
printk(XENLOG_G_ERR
"Could not revoke %pd access to IRQ%u (error %d)\n",
d, irq, err);
put_domain(d);
}
desc->arch.creator_domid = DOMID_INVALID;
}
spin_lock_irqsave(&desc->lock, flags);
@@ -381,6 +398,7 @@ int arch_init_one_irq_desc(struct irq_desc *desc)
desc->arch.vector = IRQ_VECTOR_UNASSIGNED;
desc->arch.old_vector = IRQ_VECTOR_UNASSIGNED;
desc->arch.creator_domid = DOMID_INVALID;
return 0;
}
@@ -2133,7 +2151,7 @@ int map_domain_pirq(
spin_unlock_irqrestore(&desc->lock, flags);
info = NULL;
irq = create_irq(NUMA_NO_NODE);
irq = create_irq(NUMA_NO_NODE, true);
ret = irq >= 0 ? prepare_domain_irq_pirq(d, irq, pirq + nr, &info)
: irq;
if ( ret < 0 )
@@ -2818,7 +2836,7 @@ int allocate_and_map_msi_pirq(struct domain *d, int index, int *pirq_p,
if ( irq == -1 )
{
case MAP_PIRQ_TYPE_MULTI_MSI:
irq = create_irq(NUMA_NO_NODE);
irq = create_irq(NUMA_NO_NODE, true);
}
if ( irq < nr_irqs_gsi || irq >= nr_irqs )
+1 -1
View File
@@ -722,7 +722,7 @@ static void __init ns16550_init_irq(struct serial_port *port)
struct ns16550 *uart = port->uart;
if ( uart->msi )
uart->irq = create_irq(0);
uart->irq = create_irq(0, false);
#endif
}
+1 -1
View File
@@ -766,7 +766,7 @@ static bool_t __init set_iommu_interrupt_handler(struct amd_iommu *iommu)
{
int irq, ret;
irq = create_irq(NUMA_NO_NODE);
irq = create_irq(NUMA_NO_NODE, false);
if ( irq <= 0 )
{
dprintk(XENLOG_ERR, "IOMMU: no irqs\n");
+2 -1
View File
@@ -1097,7 +1097,8 @@ static int __init iommu_set_interrupt(struct acpi_drhd_unit *drhd)
struct irq_desc *desc;
irq = create_irq(rhsa ? pxm_to_node(rhsa->proximity_domain)
: NUMA_NO_NODE);
: NUMA_NO_NODE,
false);
if ( irq <= 0 )
{
dprintk(XENLOG_ERR VTDPREFIX, "IOMMU: no irq available!\n");
+10 -1
View File
@@ -45,6 +45,11 @@ struct arch_irq_desc {
unsigned move_cleanup_count;
u8 move_in_progress : 1;
s8 used;
/*
* Weak reference to domain having permission over this IRQ (which can
* be different from the domain actually having the IRQ assigned)
*/
domid_t creator_domid;
};
/* For use with irq_desc.arch.used */
@@ -161,7 +166,11 @@ int init_irq_data(void);
void clear_irq_vector(int irq);
int irq_to_vector(int irq);
int create_irq(nodeid_t node);
/*
* If grant_access is set the current domain is given permissions over
* the created IRQ.
*/
int create_irq(nodeid_t node, bool grant_access);
void destroy_irq(unsigned int irq);
int assign_irq_vector(int irq, const cpumask_t *);
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.