Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d91d253c authored by Bart Van Assche's avatar Bart Van Assche Committed by Greg Kroah-Hartman
Browse files

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: 59c68ac3 ("iw_cm: free cm_id resources on the last deref")
Reviewed-by: default avatarZhu Yanjun <yanjun.zhu@linux.dev>
Tested-by: default avatarShin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Signed-off-by: default avatarBart Van Assche <bvanassche@acm.org>
Link: https://lore.kernel.org/r/20240605145117.397751-6-bvanassche@acm.org


Signed-off-by: default avatarLeon Romanovsky <leon@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 0818a768
Loading
Loading
Loading
Loading
+7 −4
Original line number Diff line number Diff line
@@ -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;
	unsigned long flags;
@@ -438,7 +440,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);
}

/*
@@ -449,7 +451,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);

@@ -1022,7 +1025,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))