Merge tag 'irq-urgent-2023-03-05' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 5 Mar 2023 19:19:16 +0000 (11:19 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 5 Mar 2023 19:19:16 +0000 (11:19 -0800)
Pull irq updates from Thomas Gleixner:
 "A set of updates for the interrupt susbsystem:

   - Prevent possible NULL pointer derefences in
     irq_data_get_affinity_mask() and irq_domain_create_hierarchy()

   - Take the per device MSI lock before invoking code which relies on
     it being hold

   - Make sure that MSI descriptors are unreferenced before freeing
     them. This was overlooked when the platform MSI code was converted
     to use core infrastructure and results in a fals positive warning

   - Remove dead code in the MSI subsystem

   - Clarify the documentation for pci_msix_free_irq()

   - More kobj_type constification"

* tag 'irq-urgent-2023-03-05' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  genirq/msi, platform-msi: Ensure that MSI descriptors are unreferenced
  genirq/msi: Drop dead domain name assignment
  irqdomain: Add missing NULL pointer check in irq_domain_create_hierarchy()
  genirq/irqdesc: Make kobj_type structures constant
  PCI/MSI: Clarify usage of pci_msix_free_irq()
  genirq/msi: Take the per-device MSI lock before validating the control structure
  genirq/ipi: Fix NULL pointer deref in irq_data_get_affinity_mask()

1  2 
include/linux/msi.h
kernel/irq/irqdomain.c
kernel/irq/msi.c

diff --combined include/linux/msi.h
@@@ -48,10 -48,6 +48,10 @@@ typedef struct arch_msi_msg_data 
  } __attribute__ ((packed)) arch_msi_msg_data_t;
  #endif
  
 +#ifndef arch_is_isolated_msi
 +#define arch_is_isolated_msi() false
 +#endif
 +
  /**
   * msi_msg - Representation of a MSI message
   * @address_lo:               Low 32 bits of msi message address
@@@ -635,6 -631,8 +635,8 @@@ int msi_domain_prepare_irqs(struct irq_
                            int nvec, msi_alloc_info_t *args);
  int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev,
                             int virq, int nvec, msi_alloc_info_t *args);
+ void msi_domain_depopulate_descs(struct device *dev, int virq, int nvec);
  struct irq_domain *
  __platform_msi_create_device_domain(struct device *dev,
                                    unsigned int nvec,
@@@ -653,19 -651,6 +655,19 @@@ int platform_msi_device_domain_alloc(st
  void platform_msi_device_domain_free(struct irq_domain *domain, unsigned int virq,
                                     unsigned int nvec);
  void *platform_msi_get_host_data(struct irq_domain *domain);
 +
 +bool msi_device_has_isolated_msi(struct device *dev);
 +#else /* CONFIG_GENERIC_MSI_IRQ */
 +static inline bool msi_device_has_isolated_msi(struct device *dev)
 +{
 +      /*
 +       * Arguably if the platform does not enable MSI support then it has
 +       * "isolated MSI", as an interrupt controller that cannot receive MSIs
 +       * is inherently isolated by our definition. The default definition for
 +       * arch_is_isolated_msi() is conservative and returns false anyhow.
 +       */
 +      return arch_is_isolated_msi();
 +}
  #endif /* CONFIG_GENERIC_MSI_IRQ */
  
  /* PCI specific interfaces */
diff --combined kernel/irq/irqdomain.c
@@@ -470,6 -470,31 +470,6 @@@ struct irq_domain *irq_find_matching_fw
  EXPORT_SYMBOL_GPL(irq_find_matching_fwspec);
  
  /**
 - * irq_domain_check_msi_remap - Check whether all MSI irq domains implement
 - * IRQ remapping
 - *
 - * Return: false if any MSI irq domain does not support IRQ remapping,
 - * true otherwise (including if there is no MSI irq domain)
 - */
 -bool irq_domain_check_msi_remap(void)
 -{
 -      struct irq_domain *h;
 -      bool ret = true;
 -
 -      mutex_lock(&irq_domain_mutex);
 -      list_for_each_entry(h, &irq_domain_list, link) {
 -              if (irq_domain_is_msi(h) &&
 -                  !irq_domain_hierarchical_is_msi_remap(h)) {
 -                      ret = false;
 -                      break;
 -              }
 -      }
 -      mutex_unlock(&irq_domain_mutex);
 -      return ret;
 -}
 -EXPORT_SYMBOL_GPL(irq_domain_check_msi_remap);
 -
 -/**
   * irq_set_default_host() - Set a "default" irq domain
   * @domain: default domain pointer
   *
@@@ -1147,7 -1172,8 +1147,8 @@@ struct irq_domain *irq_domain_create_hi
                domain = __irq_domain_create(fwnode, 0, ~0, 0, ops, host_data);
  
        if (domain) {
-               domain->root = parent->root;
+               if (parent)
+                       domain->root = parent->root;
                domain->parent = parent;
                domain->flags |= flags;
  
@@@ -1865,6 -1891,20 +1866,6 @@@ static void irq_domain_check_hierarchy(
        if (domain->ops->alloc)
                domain->flags |= IRQ_DOMAIN_FLAG_HIERARCHY;
  }
 -
 -/**
 - * irq_domain_hierarchical_is_msi_remap - Check if the domain or any
 - * parent has MSI remapping support
 - * @domain: domain pointer
 - */
 -bool irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain)
 -{
 -      for (; domain; domain = domain->parent) {
 -              if (irq_domain_is_msi_remap(domain))
 -                      return true;
 -      }
 -      return false;
 -}
  #else /* CONFIG_IRQ_DOMAIN_HIERARCHY */
  /**
   * irq_domain_get_irq_data - Get irq_data associated with @virq and @domain
diff --combined kernel/irq/msi.c
@@@ -830,11 -830,8 +830,8 @@@ static struct irq_domain *__msi_create_
        domain = irq_domain_create_hierarchy(parent, flags | IRQ_DOMAIN_FLAG_MSI, 0,
                                             fwnode, &msi_domain_ops, info);
  
-       if (domain) {
-               if (!domain->name && info->chip)
-                       domain->name = info->chip->name;
+       if (domain)
                irq_domain_update_bus_token(domain, info->bus_token);
-       }
  
        return domain;
  }
@@@ -1084,10 -1081,13 +1081,13 @@@ int msi_domain_populate_irqs(struct irq
        struct xarray *xa;
        int ret, virq;
  
-       if (!msi_ctrl_valid(dev, &ctrl))
-               return -EINVAL;
        msi_lock_descs(dev);
+       if (!msi_ctrl_valid(dev, &ctrl)) {
+               ret = -EINVAL;
+               goto unlock;
+       }
        ret = msi_domain_add_simple_msi_descs(dev, &ctrl);
        if (ret)
                goto unlock;
        return 0;
  
  fail:
-       for (--virq; virq >= virq_base; virq--)
+       for (--virq; virq >= virq_base; virq--) {
+               msi_domain_depopulate_descs(dev, virq, 1);
                irq_domain_free_irqs_common(domain, virq, 1);
+       }
        msi_domain_free_descs(dev, &ctrl);
  unlock:
        msi_unlock_descs(dev);
        return ret;
  }
  
+ void msi_domain_depopulate_descs(struct device *dev, int virq_base, int nvec)
+ {
+       struct msi_ctrl ctrl = {
+               .domid  = MSI_DEFAULT_DOMAIN,
+               .first  = virq_base,
+               .last   = virq_base + nvec - 1,
+       };
+       struct msi_desc *desc;
+       struct xarray *xa;
+       unsigned long idx;
+       if (!msi_ctrl_valid(dev, &ctrl))
+               return;
+       xa = &dev->msi.data->__domains[ctrl.domid].store;
+       xa_for_each_range(xa, idx, desc, ctrl.first, ctrl.last)
+               desc->irq = 0;
+ }
  /*
   * Carefully check whether the device can use reservation mode. If
   * reservation mode is enabled then the early activation will assign a
@@@ -1627,30 -1648,3 +1648,30 @@@ struct msi_domain_info *msi_get_domain_
  {
        return (struct msi_domain_info *)domain->host_data;
  }
 +
 +/**
 + * msi_device_has_isolated_msi - True if the device has isolated MSI
 + * @dev: The device to check
 + *
 + * Isolated MSI means that HW modeled by an irq_domain on the path from the
 + * initiating device to the CPU will validate that the MSI message specifies an
 + * interrupt number that the device is authorized to trigger. This must block
 + * devices from triggering interrupts they are not authorized to trigger.
 + * Currently authorization means the MSI vector is one assigned to the device.
 + *
 + * This is interesting for securing VFIO use cases where a rouge MSI (eg created
 + * by abusing a normal PCI MemWr DMA) must not allow the VFIO userspace to
 + * impact outside its security domain, eg userspace triggering interrupts on
 + * kernel drivers, a VM triggering interrupts on the hypervisor, or a VM
 + * triggering interrupts on another VM.
 + */
 +bool msi_device_has_isolated_msi(struct device *dev)
 +{
 +      struct irq_domain *domain = dev_get_msi_domain(dev);
 +
 +      for (; domain; domain = domain->parent)
 +              if (domain->flags & IRQ_DOMAIN_FLAG_ISOLATED_MSI)
 +                      return true;
 +      return arch_is_isolated_msi();
 +}
 +EXPORT_SYMBOL_GPL(msi_device_has_isolated_msi);