]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
IB/hfi1: Fix potential use-after-free in PIO and SDMA map teardown
authorLi RongQing <lirongqing@baidu.com>
Fri, 6 Feb 2026 05:08:36 +0000 (00:08 -0500)
committerJason Gunthorpe <jgg@nvidia.com>
Tue, 28 Apr 2026 14:15:49 +0000 (11:15 -0300)
The current teardown logic for dd->pio_map and dd->sdma_map frees the
structures while they might still be accessed by RCU readers. Although the
pointer is nulled under a spinlock, the memory is reclaimed before waiting
for the grace period to end.

This patch fixes the sequence by:
1. Extracting the pointer under the lock.
2. Clearing the RCU-protected pointer.
3. Waiting for readers to finish with synchronize_rcu().
4. Finally freeing the memory.

Fixes: 7724105686e7 ("IB/hfi1: add driver files")
Link: https://patch.msgid.link/r/20260206050836.5890-1-lirongqing@baidu.com
Signed-off-by: Li RongQing <lirongqing@baidu.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
drivers/infiniband/hw/hfi1/pio.c
drivers/infiniband/hw/hfi1/sdma.c

index 51afaac88c725920b4aa69692170c24dd25fdd64..9121d83bf88afe64cc554452d002e109b63bdd76 100644 (file)
@@ -1942,13 +1942,16 @@ bail:
 
 void free_pio_map(struct hfi1_devdata *dd)
 {
+       struct pio_vl_map *map;
+
        /* Free PIO map if allocated */
        if (rcu_access_pointer(dd->pio_map)) {
                spin_lock_irq(&dd->pio_map_lock);
-               pio_map_free(rcu_access_pointer(dd->pio_map));
+               map = rcu_access_pointer(dd->pio_map);
                RCU_INIT_POINTER(dd->pio_map, NULL);
                spin_unlock_irq(&dd->pio_map_lock);
                synchronize_rcu();
+               pio_map_free(map);
        }
        kfree(dd->kernel_send_context);
        dd->kernel_send_context = NULL;
index e5f442938177ebcccf3dd4dfe094fd58268cd890..cfd9dd0f7e8176c8b0675c60665d057d7e253a50 100644 (file)
@@ -1255,6 +1255,7 @@ void sdma_clean(struct hfi1_devdata *dd, size_t num_engines)
 {
        size_t i;
        struct sdma_engine *sde;
+       struct sdma_vl_map *map;
 
        if (dd->sdma_pad_dma) {
                dma_free_coherent(&dd->pcidev->dev, SDMA_PAD,
@@ -1291,10 +1292,11 @@ void sdma_clean(struct hfi1_devdata *dd, size_t num_engines)
        }
        if (rcu_access_pointer(dd->sdma_map)) {
                spin_lock_irq(&dd->sde_map_lock);
-               sdma_map_free(rcu_access_pointer(dd->sdma_map));
+               map = rcu_access_pointer(dd->sdma_map);
                RCU_INIT_POINTER(dd->sdma_map, NULL);
                spin_unlock_irq(&dd->sde_map_lock);
                synchronize_rcu();
+               sdma_map_free(map);
        }
        kfree(dd->per_sdma);
        dd->per_sdma = NULL;