Skip to content

Commit e54b000

Browse files
committed
drm/dp_mst: Ensure mst_primary pointer is valid in drm_dp_mst_handle_up_req()
While receiving an MST up request message from one thread in drm_dp_mst_handle_up_req(), the MST topology could be removed from another thread via drm_dp_mst_topology_mgr_set_mst(false), freeing mst_primary and setting drm_dp_mst_topology_mgr::mst_primary to NULL. This could lead to a NULL deref/use-after-free of mst_primary in drm_dp_mst_handle_up_req(). Avoid the above by holding a reference for mst_primary in drm_dp_mst_handle_up_req() while it's used. v2: Fix kfreeing the request if getting an mst_primary reference fails. Cc: Lyude Paul <lyude@redhat.com> Reviewed-by: Lyude Paul <lyude@redhat.com> (v1) Signed-off-by: Imre Deak <imre.deak@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20241204132007.3132494-1-imre.deak@intel.com
1 parent 3f61185 commit e54b000

File tree

1 file changed

+18
-6
lines changed

1 file changed

+18
-6
lines changed

drivers/gpu/drm/display/drm_dp_mst_topology.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4109,9 +4109,10 @@ static void drm_dp_mst_up_req_work(struct work_struct *work)
41094109
static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
41104110
{
41114111
struct drm_dp_pending_up_req *up_req;
4112+
struct drm_dp_mst_branch *mst_primary;
41124113

41134114
if (!drm_dp_get_one_sb_msg(mgr, true, NULL))
4114-
goto out;
4115+
goto out_clear_reply;
41154116

41164117
if (!mgr->up_req_recv.have_eomt)
41174118
return 0;
@@ -4129,10 +4130,19 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
41294130
drm_dbg_kms(mgr->dev, "Received unknown up req type, ignoring: %x\n",
41304131
up_req->msg.req_type);
41314132
kfree(up_req);
4132-
goto out;
4133+
goto out_clear_reply;
4134+
}
4135+
4136+
mutex_lock(&mgr->lock);
4137+
mst_primary = mgr->mst_primary;
4138+
if (!mst_primary || !drm_dp_mst_topology_try_get_mstb(mst_primary)) {
4139+
mutex_unlock(&mgr->lock);
4140+
kfree(up_req);
4141+
goto out_clear_reply;
41334142
}
4143+
mutex_unlock(&mgr->lock);
41344144

4135-
drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, up_req->msg.req_type,
4145+
drm_dp_send_up_ack_reply(mgr, mst_primary, up_req->msg.req_type,
41364146
false);
41374147

41384148
if (up_req->msg.req_type == DP_CONNECTION_STATUS_NOTIFY) {
@@ -4149,13 +4159,13 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
41494159
conn_stat->peer_device_type);
41504160

41514161
mutex_lock(&mgr->probe_lock);
4152-
handle_csn = mgr->mst_primary->link_address_sent;
4162+
handle_csn = mst_primary->link_address_sent;
41534163
mutex_unlock(&mgr->probe_lock);
41544164

41554165
if (!handle_csn) {
41564166
drm_dbg_kms(mgr->dev, "Got CSN before finish topology probing. Skip it.");
41574167
kfree(up_req);
4158-
goto out;
4168+
goto out_put_primary;
41594169
}
41604170
} else if (up_req->msg.req_type == DP_RESOURCE_STATUS_NOTIFY) {
41614171
const struct drm_dp_resource_status_notify *res_stat =
@@ -4172,7 +4182,9 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
41724182
mutex_unlock(&mgr->up_req_lock);
41734183
queue_work(system_long_wq, &mgr->up_req_work);
41744184

4175-
out:
4185+
out_put_primary:
4186+
drm_dp_mst_topology_put_mstb(mst_primary);
4187+
out_clear_reply:
41764188
memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
41774189
return 0;
41784190
}

0 commit comments

Comments
 (0)