[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v5 4/6] xen/x86: Allow stubdom access to irq created for msi.



On Wed, Jul 17, 2019 at 05:09:12PM +0200, Marek Marczykowski-Górecki wrote:
> On Wed, Jul 17, 2019 at 11:54:35AM +0200, Roger Pau Monné wrote:
> > On Wed, Jul 17, 2019 at 03:00:42AM +0200, Marek Marczykowski-Górecki wrote:
> > > @@ -220,14 +237,22 @@ void destroy_irq(unsigned int irq)
> > >  
> > >      BUG_ON(!MSI_IRQ(irq));
> > >  
> > > -    if ( hardware_domain )
> > > +    if ( desc->creator_domid != DOMID_INVALID )
> > >      {
> > > -        int err = irq_deny_access(hardware_domain, irq);
> > > +        struct domain *d = get_domain_by_id(desc->creator_domid);
> > >  
> > > -        if ( err )
> > > -            printk(XENLOG_G_ERR
> > > -                   "Could not revoke Dom0 access to IRQ%u (error %d)\n",
> > > -                   irq, err);
> > > +        if ( d && irq_access_permitted(d, irq) ) {
> > > +            int err;
> > > +
> > > +            err = irq_deny_access(d, irq);
> > > +            if ( err )
> > > +                printk(XENLOG_G_ERR
> > > +                       "Could not revoke Dom%u access to IRQ%u (error 
> > > %d)\n",
> > > +                       d->domain_id, irq, err);
> > > +        }
> > > +
> > > +        if ( d )
> > > +            put_domain(d);
> > 
> > Don't you need to set creator_domid = DOMID_INVALID in destroy_irq at
> > some point?
> > 
> > Or else a failure in create_irq could leak the irq to it's previous
> > owner. Note that init_one_irq_desc would only init the fields the
> > first time the IRQ is used, but not for subsequent usages AFAICT.
> 
> I assumed init_one_irq_desc do the work on subsequent usages too. If not,
> indeed I need to modify creator_domid in few more places.

I don't think so, init_one_irq_desc will only init the fields if
handler == NULL, which will only happen the first time the IRQ is
used, afterwards handler is set to &no_irq_type by destroy_irq.

Just setting creator_domid = DOMID_INVALID in destroy_irq and adding
the assert to create_irq should be enough AFAICT, since those
functions are used exclusively by non-shared IRQs (MSI and MSI-X).

> > >      }
> > >  
> > >      spin_lock_irqsave(&desc->lock, flags);
> > > @@ -2058,7 +2083,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, get_dm_domain(d));
> > 
> > Isn't it fine to just use current->domain here directly?
> > 
> > It's always going to be the current domain the one that calls
> > map_domain_pirq in order to get a PIRQ mapped for it's target
> > domain I think.
> 
> I wasn't sure if that's true if all the cases. Especially if hardware
> domain != toolstack domain. How is it then? Is it hardware domain
> calling map_domain_pirq in that case?

But then it's going to be the hardware domain the one that runs the
QEMU instance, and hence the one that issues the hypercalls to
map/unmap PIRQs to a target domain?

ie: the PCI backend (either pciback or QEMU) is not going to run on
the toolstack domain.

I'm afraid I don't see a case where current->domain isn't the domain
also requiring permissions over the IRQ, but I could be wrong. Can you
come up with a detailed scenario where this might happen?

> 
> > >              ret = irq >= 0 ? prepare_domain_irq_pirq(d, irq, pirq + nr, 
> > > &info)
> > >                             : irq;
> > >              if ( ret < 0 )
> > > @@ -2691,7 +2716,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, get_dm_domain(d));
> > >          }
> > >  
> > >          if ( irq < nr_irqs_gsi || irq >= nr_irqs )
> > > diff --git a/xen/common/irq.c b/xen/common/irq.c
> > > index f42512d..42b27a9 100644
> > > --- a/xen/common/irq.c
> > > +++ b/xen/common/irq.c
> > > @@ -16,6 +16,7 @@ int init_one_irq_desc(struct irq_desc *desc)
> > >      spin_lock_init(&desc->lock);
> > >      cpumask_setall(desc->affinity);
> > >      INIT_LIST_HEAD(&desc->rl_link);
> > > +    desc->creator_domid = DOMID_INVALID;
> > >  
> > >      err = arch_init_one_irq_desc(desc);
> > >      if ( err )
> > > diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
> > > index 189e121..ccc8b04 100644
> > > --- a/xen/drivers/char/ns16550.c
> > > +++ b/xen/drivers/char/ns16550.c
> > > @@ -719,7 +719,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, NULL);
> > >  #endif
> > >  }
> > >  
> > > diff --git a/xen/drivers/passthrough/amd/iommu_init.c 
> > > b/xen/drivers/passthrough/amd/iommu_init.c
> > > index 4e76b26..50785e0 100644
> > > --- a/xen/drivers/passthrough/amd/iommu_init.c
> > > +++ b/xen/drivers/passthrough/amd/iommu_init.c
> > > @@ -781,7 +781,7 @@ static bool_t __init 
> > > set_iommu_interrupt_handler(struct amd_iommu *iommu)
> > >      hw_irq_controller *handler;
> > >      u16 control;
> > >  
> > > -    irq = create_irq(NUMA_NO_NODE);
> > > +    irq = create_irq(NUMA_NO_NODE, NULL);
> > >      if ( irq <= 0 )
> > >      {
> > >          dprintk(XENLOG_ERR, "IOMMU: no irqs\n");
> > > diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
> > > index e886894..507b3d1 100644
> > > --- a/xen/drivers/passthrough/pci.c
> > > +++ b/xen/drivers/passthrough/pci.c
> > > @@ -845,6 +845,9 @@ int pci_remove_device(u16 seg, u8 bus, u8 devfn)
> > >      list_for_each_entry ( pdev, &pseg->alldevs_list, alldevs_list )
> > >          if ( pdev->bus == bus && pdev->devfn == devfn )
> > >          {
> > > +            ret = -EBUSY;
> > > +            if ( pdev->domain && pdev->domain != hardware_domain )
> > > +                break;
> > 
> > This seems like an unlrelated fix?
> > 
> > ie: preventing device removal while in use by a domain different than
> > dom0?
> 
> Indeed it may warrant separate commit now.
> 
> > Note that you don't need the pdev->domain != NULL check, just doing
> > pdev->domain != hardware_domain seems enough, since you don't
> > dereference the pdev->domain pointer in the expression (unless I'm
> > missing other usages below).
> 
> I don't want to prevent removal if pdev->domain is NULL (if that's even
> possible).

But if pdev->domain == NULL, then it's certainly going to be different
from hardware_domain, so just using pdev->domain != hardware_domain
achieves both.

> > >              ret = iommu_remove_device(pdev);
> > >              if ( pdev->domain )
> > >                  list_del(&pdev->domain_list);
> > > diff --git a/xen/drivers/passthrough/vtd/iommu.c 
> > > b/xen/drivers/passthrough/vtd/iommu.c
> > > index 8b27d7e..79f9682 100644
> > > --- a/xen/drivers/passthrough/vtd/iommu.c
> > > +++ b/xen/drivers/passthrough/vtd/iommu.c
> > > @@ -1138,7 +1138,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,
> > > +                     NULL);
> > >      if ( irq <= 0 )
> > >      {
> > >          dprintk(XENLOG_ERR VTDPREFIX, "IOMMU: no irq available!\n");
> > > diff --git a/xen/include/asm-x86/irq.h b/xen/include/asm-x86/irq.h
> > > index c0c6e7c..5b24428 100644
> > > --- a/xen/include/asm-x86/irq.h
> > > +++ b/xen/include/asm-x86/irq.h
> > > @@ -155,7 +155,7 @@ int  init_irq_data(void);
> > >  void clear_irq_vector(int irq);
> > >  
> > >  int irq_to_vector(int irq);
> > > -int create_irq(nodeid_t node);
> > > +int create_irq(nodeid_t node, struct domain *d);
> > >  void destroy_irq(unsigned int irq);
> > >  int assign_irq_vector(int irq, const cpumask_t *);
> > >  
> > > diff --git a/xen/include/xen/irq.h b/xen/include/xen/irq.h
> > > index 586b783..c7a6a83 100644
> > > --- a/xen/include/xen/irq.h
> > > +++ b/xen/include/xen/irq.h
> > > @@ -91,6 +91,7 @@ typedef struct irq_desc {
> > >      spinlock_t lock;
> > >      struct arch_irq_desc arch;
> > >      cpumask_var_t affinity;
> > > +    domid_t creator_domid; /* weak reference to domain handling this IRQ 
> > > */
> > 
> > I feel like handling is too vague here, but I'm not a native speaker
> > so I'm not sure. I would maybe write:
> > 
> > ... domain having permissions over this IRQ (which can be different
> > from the domain actually having the IRQ assigned) */
> > 
> > Which I think is less ambiguous.
> 
> I wanted to fit the comment in one line. But your version indeed may be
> better.

I would always error towards being more verbose, even if that means
using more that one line. As said, I don't think the comment is wrong,
just feel it could be more detailed.

Thanks, Roger.

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.