Linux RDMA and InfiniBand development
 help / color / mirror / Atom feed
* [PATCH] RDMA/irdma: publish APBVT entries after hardware setup
@ 2026-11-11  9:25 Jaeyeong Lee
  2026-11-11  9:36 ` sashiko-bot
  2026-11-11 15:15 ` Jacob Moroni
  0 siblings, 2 replies; 3+ messages in thread
From: Jaeyeong Lee @ 2026-11-11  9:25 UTC (permalink / raw)
  To: Tatyana Nikolova, linux-rdma
  Cc: Jason Gunthorpe, Leon Romanovsky, Shiraz Saleem, Mustafa Ismail,
	Gustavo A . R . Silva, linux-kernel, stable

irdma_add_apbvt() inserts a new entry into apbvt_hash_tbl before
sending the CQP command that creates the hardware entry. If the command
fails, the entry is freed without being removed from the hash table. A
later lookup of the same port traverses the freed entry.

Removing the entry on failure is not sufficient because another thread
can find it and increment use_cnt while the CQP command is in progress.

Serialize APBVT additions and publish new entries only after the hardware
command succeeds. Since the allocation no longer runs under apbvt_lock,
use GFP_KERNEL.

The issue was found by static analysis and confirmed with a KASAN
reproducer that forces the CQP failure and retries the same port.

BUG: KASAN: slab-use-after-free in irdma_add_apbvt+0xa0/0x280 [irdma]
Read of size 2 at addr ffff8880092d10d4 by task insmod/72

Call Trace:
 irdma_add_apbvt+0xa0/0x280 [irdma]
 init_module+0x232/0xff0 [irdma_apbvt_repro]
 do_one_initcall+0x13d/0x340

Allocated by task 72:
 irdma_add_apbvt+0xda/0x280 [irdma]
 init_module+0x210/0xff0 [irdma_apbvt_repro]

Freed by task 72:
 kfree+0x155/0x470
 irdma_add_apbvt+0x1e9/0x280 [irdma]
 init_module+0x210/0xff0 [irdma_apbvt_repro]

Fixes: 44d9e52977a1 ("RDMA/irdma: Implement device initialization definitions")
Cc: stable@vger.kernel.org
Signed-off-by: Jaeyeong Lee <lee@jaeyeong.cc>
---
 drivers/infiniband/hw/irdma/cm.c |  1 +
 drivers/infiniband/hw/irdma/cm.h |  3 ++-
 drivers/infiniband/hw/irdma/hw.c | 28 ++++++++++++++++------------
 3 files changed, 19 insertions(+), 13 deletions(-)

diff --git a/drivers/infiniband/hw/irdma/cm.c b/drivers/infiniband/hw/irdma/cm.c
index 91c0e7298283..bc30e465c670 100644
--- a/drivers/infiniband/hw/irdma/cm.c
+++ b/drivers/infiniband/hw/irdma/cm.c
@@ -3281,6 +3281,7 @@ int irdma_setup_cm_core(struct irdma_device *iwdev, u8 rdma_ver)
 	spin_lock_init(&cm_core->ht_lock);
 	spin_lock_init(&cm_core->listen_list_lock);
 	spin_lock_init(&cm_core->apbvt_lock);
+	mutex_init(&cm_core->apbvt_add_mutex);
 	switch (rdma_ver) {
 	case IRDMA_GEN_1:
 		cm_core->form_cm_frame = irdma_form_uda_cm_frame;
diff --git a/drivers/infiniband/hw/irdma/cm.h b/drivers/infiniband/hw/irdma/cm.h
index 48ee285cf745..6c5f4335f09d 100644
--- a/drivers/infiniband/hw/irdma/cm.h
+++ b/drivers/infiniband/hw/irdma/cm.h
@@ -357,7 +357,8 @@ struct irdma_cm_core {
 	struct workqueue_struct *event_wq;
 	spinlock_t ht_lock; /* protect CM node (active side) list */
 	spinlock_t listen_list_lock; /* protect listener list */
-	spinlock_t apbvt_lock; /*serialize apbvt add/del entries*/
+	spinlock_t apbvt_lock; /* serialize APBVT entry access */
+	struct mutex apbvt_add_mutex; /* serialize APBVT hardware adds */
 	u64 stats_nodes_created;
 	u64 stats_nodes_destroyed;
 	u64 stats_listen_created;
diff --git a/drivers/infiniband/hw/irdma/hw.c b/drivers/infiniband/hw/irdma/hw.c
index c345cc654256..23ad18167607 100644
--- a/drivers/infiniband/hw/irdma/hw.c
+++ b/drivers/infiniband/hw/irdma/hw.c
@@ -2474,29 +2474,33 @@ struct irdma_apbvt_entry *irdma_add_apbvt(struct irdma_device *iwdev, u16 port)
 	struct irdma_apbvt_entry *entry;
 	unsigned long flags;
 
+	mutex_lock(&cm_core->apbvt_add_mutex);
 	spin_lock_irqsave(&cm_core->apbvt_lock, flags);
 	entry = irdma_lookup_apbvt_entry(cm_core, port);
-	if (entry) {
-		spin_unlock_irqrestore(&cm_core->apbvt_lock, flags);
-		return entry;
-	}
+	spin_unlock_irqrestore(&cm_core->apbvt_lock, flags);
+	if (entry)
+		goto out;
 
-	entry = kzalloc_obj(*entry, GFP_ATOMIC);
-	if (!entry) {
-		spin_unlock_irqrestore(&cm_core->apbvt_lock, flags);
-		return NULL;
-	}
+	entry = kzalloc_obj(*entry, GFP_KERNEL);
+	if (!entry)
+		goto out;
 
 	entry->port = port;
 	entry->use_cnt = 1;
-	hash_add(cm_core->apbvt_hash_tbl, &entry->hlist, entry->port);
-	spin_unlock_irqrestore(&cm_core->apbvt_lock, flags);
 
 	if (irdma_cqp_manage_apbvt_cmd(iwdev, port, true)) {
 		kfree(entry);
-		return NULL;
+		entry = NULL;
+		goto out;
 	}
 
+	spin_lock_irqsave(&cm_core->apbvt_lock, flags);
+	hash_add(cm_core->apbvt_hash_tbl, &entry->hlist, entry->port);
+	spin_unlock_irqrestore(&cm_core->apbvt_lock, flags);
+
+out:
+	mutex_unlock(&cm_core->apbvt_add_mutex);
+
 	return entry;
 }
 
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-11-11 15:15 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-11  9:25 [PATCH] RDMA/irdma: publish APBVT entries after hardware setup Jaeyeong Lee
2026-11-11  9:36 ` sashiko-bot
2026-11-11 15:15 ` Jacob Moroni

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox