[PATCH 3/3] rdma: Get drbd_path->kref when get drbd_path by addr
"zhengbing.huang" <[email protected]> Wed, 9 Jul 2025 10:55:52 +0800
| Newsgroups | dev.linux.lists.drbd-dev |
|---|---|
| Message-ID | <[email protected]> |
In the dtr_cma_accept() function, after obtain the drbd_path through peer_addr, without take a reference, the drbd_path may be released concurrently, leade to a use-after-free. So when we obtain drbd_path, we add a reference count. Signed-off-by: zhengbing.huang <[email protected]> --- drbd/drbd_transport_rdma.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drbd/drbd_transport_rdma.c b/drbd/drbd_transport_rdma.c index 442dd8e89..68c668f7f 100644 --- a/drbd/drbd_transport_rdma.c +++ b/drbd/drbd_transport_rdma.c @@ -969,6 +969,8 @@ static int dtr_cma_accept(struct dtr_listener *listener, struct rdma_cm_id *new_ spin_lock(&listener->listener.waiters_lock); drbd_path = drbd_find_path_by_addr(&listener->listener, peer_addr); + if (drbd_path) + kref_get(&drbd_path->kref); spin_unlock(&listener->listener.waiters_lock); if (!drbd_path) { @@ -997,16 +999,13 @@ static int dtr_cma_accept(struct dtr_listener *listener, struct rdma_cm_id *new_ path = container_of(drbd_path, struct dtr_path, path); cs = &path->cs; - if (atomic_read(&cs->passive_state) < PCS_CONNECTING) { - rdma_reject(new_cm_id, NULL, 0, IB_CM_REJ_CONSUMER_DEFINED); - return -EAGAIN; - } + if (atomic_read(&cs->passive_state) < PCS_CONNECTING) + goto reject; cm = dtr_alloc_cm(path); if (!cm) { pr_err("rejecting connecting since -ENOMEM for cm\n"); - rdma_reject(new_cm_id, NULL, 0, IB_CM_REJ_CONSUMER_DEFINED); - return -EAGAIN; + goto reject; } cm->state = DSM_CONNECT_REQ; @@ -1024,17 +1023,21 @@ static int dtr_cma_accept(struct dtr_listener *listener, struct rdma_cm_id *new_ /* Gifting the initial kref to the path->cm pointer */ err = dtr_path_prepare(path, cm, false); if (err) { - rdma_reject(new_cm_id, NULL, 0, IB_CM_REJ_CONSUMER_DEFINED); /* Returning the cm via ret_cm and an error causes the caller to put one ref */ - - return -EAGAIN; + goto reject; } + kref_put(&drbd_path->kref, drbd_destroy_path); err = rdma_accept(new_cm_id, &dtr_conn_param); if (err) kref_put(&cm->kref, dtr_destroy_cm); return err; + +reject: + rdma_reject(new_cm_id, NULL, 0, IB_CM_REJ_CONSUMER_DEFINED); + kref_put(&drbd_path->kref, drbd_destroy_path); + return -EAGAIN; } static int dtr_start_try_connect(struct dtr_connect_state *cs) -- 2.43.0