[PATCH] RDMA/irdma: avoid use-after-free in icrdma_remove
From: Guangshuo Li
Date: Mon Sep 14 2026 - 08:59:31 EST
icrdma_remove() dereferences iwdev after calling
irdma_ib_unregister_device():
irdma_ib_unregister_device(iwdev)
-> ib_unregister_device(&iwdev->ibdev)
-> __ib_unregister_device()
-> ib_dealloc_device()
irdma registers irdma_ib_dealloc_device() as the dealloc_driver
callback in its ib_device_ops. The RDMA core explicitly documents
ib_unregister_device() that when ops.dealloc_driver is used, ib_dev
will be freed upon return from the function.
The ib_device is embedded in struct irdma_device and iwdev itself was
allocated by ib_alloc_device(irdma_device, ibdev). Consequently, once
irdma_ib_unregister_device() returns, iwdev must no longer be
dereferenced.
However, icrdma_remove() currently accesses iwdev->rf afterwards when
deinitializing interrupts, destroying ah_tbl_lock, and freeing rf.
Although the final ib_device storage is released with kfree_rcu(), the
object lifetime has already ended and callers must not rely on the RCU
grace period to continue dereferencing iwdev.
Save iwdev->rf before unregistering the RDMA device and use the saved
pointer for the remaining cleanup.
This issue was found by manual code inspection.
Fixes: 8498a30e1b94 ("RDMA/irdma: Register auxiliary driver and implement private channel OPs")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Guangshuo Li <lgs201920130244@xxxxxxxxx>
---
drivers/infiniband/hw/irdma/icrdma_if.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/infiniband/hw/irdma/icrdma_if.c b/drivers/infiniband/hw/irdma/icrdma_if.c
index 4b451d8482a4..f405ef761f84 100644
--- a/drivers/infiniband/hw/irdma/icrdma_if.c
+++ b/drivers/infiniband/hw/irdma/icrdma_if.c
@@ -318,14 +318,15 @@ static void icrdma_remove(struct auxiliary_device *aux_dev)
container_of(aux_dev, struct iidc_rdma_core_auxiliary_dev, adev);
struct iidc_rdma_core_dev_info *cdev_info = idc_adev->cdev_info;
struct irdma_device *iwdev = auxiliary_get_drvdata(aux_dev);
- u8 rdma_ver = iwdev->rf->rdma_ver;
+ struct irdma_pci_f *rf = iwdev->rf;
+ u8 rdma_ver = rf->rdma_ver;
ice_rdma_update_vsi_filter(cdev_info, iwdev->vsi_num, false);
irdma_ib_unregister_device(iwdev);
- icrdma_deinit_interrupts(iwdev->rf, cdev_info);
- mutex_destroy(&iwdev->rf->ah_tbl_lock);
+ icrdma_deinit_interrupts(rf, cdev_info);
+ mutex_destroy(&rf->ah_tbl_lock);
- kfree(iwdev->rf);
+ kfree(rf);
pr_debug("INIT: Gen[%d] func[%d] device remove success\n",
rdma_ver, PCI_FUNC(cdev_info->pdev->devfn));
--
2.43.0