Re: revert bab65e48cb064 PCI/MSI Sanitize MSI-X checks

From: Linus Torvalds
Date: Fri Apr 07 2023 - 15:26:52 EST


On Fri, Apr 7, 2023 at 5:25 AM David Laight <David.Laight@xxxxxxxxxx> wrote:
>
> I think it depends on why the driver is asking for more
> interrupts than the hardware supports.
> Potentially the driver could do:
> for (i = 0; i < 8; i++)
> msix_tbl[i].entry = 2 * i;
> if the hardware supports 8 interrupts perhaps it
> should return 4?

Hmm.

Something like this might get that case right too. Again - entirely
untested, but looks superficially sane to me.

It just returns how many of the msix_entry[] entries can be used (or
negative for error). So then the (only) caller can just say "is that
still enough for what we required". Seems reasonable, and would get
that non-contiguous case right, I think.

Thomas?

I'm going to drop this and assume I'll get a pull from you with what
you consider the proper fix, but since I was looking at this anyway, I
decided I might as well send out this RFC patch.

Linus
drivers/pci/msi/msi.c | 30 +++++++++++++++++-------------
1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/drivers/pci/msi/msi.c b/drivers/pci/msi/msi.c
index 1f716624ca56..d151bde8b8e0 100644
--- a/drivers/pci/msi/msi.c
+++ b/drivers/pci/msi/msi.c
@@ -750,32 +750,33 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
return ret;
}

-static bool pci_msix_validate_entries(struct pci_dev *dev, struct msix_entry *entries,
- int nvec, int hwsize)
+static int pci_msix_validate_entries(struct pci_dev *dev, struct msix_entry *entries,
+ int nvec, int hwsize)
{
bool nogap;
- int i, j;
+ int maxvec;

if (!entries)
- return true;
+ return nvec;

nogap = pci_msi_domain_supports(dev, MSI_FLAG_MSIX_CONTIGUOUS, DENY_LEGACY);

- for (i = 0; i < nvec; i++) {
+ maxvec = -EINVAL;
+ for (int i = 0; i < nvec; i++) {
/* Entry within hardware limit? */
- if (entries[i].entry >= hwsize)
- return false;
+ if (entries[i].entry < hwsize)
+ maxvec = i+1;

/* Check for duplicate entries */
- for (j = i + 1; j < nvec; j++) {
+ for (int j = i + 1; j < nvec; j++) {
if (entries[i].entry == entries[j].entry)
- return false;
+ return -EINVAL;
}
/* Check for unsupported gaps */
if (nogap && entries[i].entry != i)
- return false;
+ return -EINVAL;
}
- return true;
+ return maxvec;
}

int __pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, int minvec,
@@ -805,8 +806,11 @@ int __pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, int
if (hwsize < 0)
return hwsize;

- if (!pci_msix_validate_entries(dev, entries, nvec, hwsize))
- return -EINVAL;
+ nvec = pci_msix_validate_entries(dev, entries, nvec, hwsize);
+ if (nvec < 0)
+ return nvec;
+ if (nvec < minvec)
+ return -ENOSPC;

if (hwsize < nvec) {
/* Keep the IRQ virtual hackery working */