RDMA/iwcm: Fix a use-after-free related to destroying CM IDs
commit aee2424246f9f1dadc33faa78990c1e2eb7826e4 upstream.
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: stable@vger.kernel.org
Fixes: 59c68ac31e
("iw_cm: free cm_id resources on the last deref")
Reviewed-by: Zhu Yanjun <yanjun.zhu@linux.dev>
Tested-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Link: https://lore.kernel.org/r/20240605145117.397751-6-bvanassche@acm.org
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Родитель
4488eef06d
Коммит
557d035fe8
|
@ -369,8 +369,10 @@ EXPORT_SYMBOL(iw_cm_disconnect);
|
|||
*
|
||||
* Clean up all resources associated with the connection and release
|
||||
* the initial reference taken by iw_create_cm_id.
|
||||
*
|
||||
* Returns true if and only if the last cm_id_priv reference has been dropped.
|
||||
*/
|
||||
static void destroy_cm_id(struct iw_cm_id *cm_id)
|
||||
static bool destroy_cm_id(struct iw_cm_id *cm_id)
|
||||
{
|
||||
struct iwcm_id_private *cm_id_priv;
|
||||
struct ib_qp *qp;
|
||||
|
@ -440,7 +442,7 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
|
|||
iwpm_remove_mapping(&cm_id->local_addr, RDMA_NL_IWCM);
|
||||
}
|
||||
|
||||
(void)iwcm_deref_id(cm_id_priv);
|
||||
return iwcm_deref_id(cm_id_priv);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -451,7 +453,8 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
|
|||
*/
|
||||
void iw_destroy_cm_id(struct iw_cm_id *cm_id)
|
||||
{
|
||||
destroy_cm_id(cm_id);
|
||||
if (!destroy_cm_id(cm_id))
|
||||
flush_workqueue(iwcm_wq);
|
||||
}
|
||||
EXPORT_SYMBOL(iw_destroy_cm_id);
|
||||
|
||||
|
@ -1035,7 +1038,7 @@ static void cm_work_handler(struct work_struct *_work)
|
|||
if (!test_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags)) {
|
||||
ret = process_event(cm_id_priv, &levent);
|
||||
if (ret)
|
||||
destroy_cm_id(&cm_id_priv->id);
|
||||
WARN_ON_ONCE(destroy_cm_id(&cm_id_priv->id));
|
||||
} else
|
||||
pr_debug("dropping event %d\n", levent.event);
|
||||
if (iwcm_deref_id(cm_id_priv))
|
||||
|
|
Загрузка…
Ссылка в новой задаче