RDMA/efa: Keep admin queues alive while IRQ is registered

The management IRQ handler accesses both the admin completion queue and the
async event queue. The driver registered the IRQ before constructing these
queues and destroyed them before freeing the IRQ, so the handler's lifetime
was not contained by the resources it accesses.

Initialize the queues with interrupts masked, request the IRQ, and then
switch to interrupt mode. On removal, reset the device and free the IRQ
before destroying the queues. Also reset the device before destroying the
queues if IRQ registration fails, because the device already has their DMA
addresses.

Fixes: b7f5e880f3 ("RDMA/efa: Add the efa module")
Link: https://patch.msgid.link/20260907-use-after-free-of-admin-queue-struct-v1-1-dd9d9267fbf4@nvidia.com
Reviewed-by: Michael Margolin <mrgolin@amazon.com>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
This commit is contained in:
Leon Romanovsky 2026-09-10 09:35:13 -04:00
parent 33fb59da49
commit e08aca85c0
2 changed files with 10 additions and 9 deletions

View File

@ -850,7 +850,7 @@ int efa_com_admin_init(struct efa_com_dev *edev,
aq->dmadev = edev->dmadev;
aq->efa_dev = edev->efa_dev;
set_bit(EFA_AQ_STATE_POLLING_BIT, &aq->state);
efa_com_set_admin_polling_mode(edev, true);
sema_init(&aq->avail_cmds, aq->depth);
@ -868,8 +868,6 @@ int efa_com_admin_init(struct efa_com_dev *edev,
if (err)
goto err_destroy_sq;
efa_com_set_admin_polling_mode(edev, false);
err = efa_com_admin_init_aenq(edev, aenq_handlers);
if (err)
goto err_destroy_cq;

View File

@ -619,18 +619,21 @@ static struct efa_dev *efa_probe_device(struct pci_dev *pdev)
edev->aq.msix_vector_idx = dev->admin_msix_vector_idx;
edev->aenq.msix_vector_idx = dev->admin_msix_vector_idx;
err = efa_set_mgmnt_irq(dev);
err = efa_com_admin_init(edev, &aenq_handlers);
if (err)
goto err_disable_msix;
err = efa_com_admin_init(edev, &aenq_handlers);
err = efa_set_mgmnt_irq(dev);
if (err)
goto err_free_mgmnt_irq;
goto err_destroy_admin;
efa_com_set_admin_polling_mode(edev, false);
return dev;
err_free_mgmnt_irq:
efa_free_irq(dev, &dev->admin_irq);
err_destroy_admin:
efa_com_dev_reset(edev, EFA_REGS_RESET_INIT_ERR);
efa_com_admin_destroy(edev);
err_disable_msix:
efa_disable_msix(dev);
err_reg_read_destroy:
@ -654,8 +657,8 @@ static void efa_remove_device(struct pci_dev *pdev,
edev = &dev->edev;
efa_com_dev_reset(edev, reset_reason);
efa_com_admin_destroy(edev);
efa_free_irq(dev, &dev->admin_irq);
efa_com_admin_destroy(edev);
efa_disable_msix(dev);
efa_com_mmio_reg_read_destroy(edev);
devm_iounmap(&pdev->dev, edev->reg_bar);