Skip to content

Commit aee2424

Browse files
bvanasscherleon
authored andcommitted
RDMA/iwcm: Fix a use-after-free related to destroying CM IDs
iw_conn_req_handler() associates a new struct rdma_id_private (conn_id) with an existing struct iw_cm_id (cm_id) as follows: conn_id->cm_id.iw = cm_id; cm_id->context = conn_id; cm_id->cm_handler = cma_iw_handler; rdma_destroy_id() frees both the cm_id and the struct rdma_id_private. Make sure that cm_work_handler() does not trigger a use-after-free by only freeing of the struct rdma_id_private after all pending work has finished. Cc: [email protected] Fixes: 59c68ac ("iw_cm: free cm_id resources on the last deref") Reviewed-by: Zhu Yanjun <[email protected]> Tested-by: Shin'ichiro Kawasaki <[email protected]> Signed-off-by: Bart Van Assche <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Leon Romanovsky <[email protected]>
1 parent a1babdb commit aee2424

File tree

1 file changed

+7
-4
lines changed

1 file changed

+7
-4
lines changed

drivers/infiniband/core/iwcm.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,10 @@ EXPORT_SYMBOL(iw_cm_disconnect);
368368
*
369369
* Clean up all resources associated with the connection and release
370370
* the initial reference taken by iw_create_cm_id.
371+
*
372+
* Returns true if and only if the last cm_id_priv reference has been dropped.
371373
*/
372-
static void destroy_cm_id(struct iw_cm_id *cm_id)
374+
static bool destroy_cm_id(struct iw_cm_id *cm_id)
373375
{
374376
struct iwcm_id_private *cm_id_priv;
375377
struct ib_qp *qp;
@@ -439,7 +441,7 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
439441
iwpm_remove_mapping(&cm_id->local_addr, RDMA_NL_IWCM);
440442
}
441443

442-
(void)iwcm_deref_id(cm_id_priv);
444+
return iwcm_deref_id(cm_id_priv);
443445
}
444446

445447
/*
@@ -450,7 +452,8 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
450452
*/
451453
void iw_destroy_cm_id(struct iw_cm_id *cm_id)
452454
{
453-
destroy_cm_id(cm_id);
455+
if (!destroy_cm_id(cm_id))
456+
flush_workqueue(iwcm_wq);
454457
}
455458
EXPORT_SYMBOL(iw_destroy_cm_id);
456459

@@ -1031,7 +1034,7 @@ static void cm_work_handler(struct work_struct *_work)
10311034
if (!test_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags)) {
10321035
ret = process_event(cm_id_priv, &levent);
10331036
if (ret)
1034-
destroy_cm_id(&cm_id_priv->id);
1037+
WARN_ON_ONCE(destroy_cm_id(&cm_id_priv->id));
10351038
} else
10361039
pr_debug("dropping event %d\n", levent.event);
10371040
if (iwcm_deref_id(cm_id_priv))

0 commit comments

Comments
 (0)