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

Commit 4772ff03 authored by Maarten Lankhorst's avatar Maarten Lankhorst Committed by Jani Nikula
Browse files

drm/dp/mst: Remove port after removing connector.



The port is removed synchronously, but the connector delayed.
This causes a use after free which can cause a kernel BUG with
slug_debug=FPZU. This is fixed by freeing the port after the
connector.

This fixes a regression introduced with
6b8eeca6
"drm/dp/mst: close deadlock in connector destruction."

Cc: stable@vger.kernel.org
Cc: Dave Airlie <airlied@redhat.com>
Signed-off-by: default avatarMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: default avatarJani Nikula <jani.nikula@intel.com>
parent 5677d67a
Loading
Loading
Loading
Loading
+13 −6
Original line number Diff line number Diff line
@@ -873,9 +873,10 @@ static void drm_dp_destroy_port(struct kref *kref)
		   from an EDID retrieval */
		if (port->connector) {
			mutex_lock(&mgr->destroy_connector_lock);
			list_add(&port->connector->destroy_list, &mgr->destroy_connector_list);
			list_add(&port->next, &mgr->destroy_connector_list);
			mutex_unlock(&mgr->destroy_connector_lock);
			schedule_work(&mgr->destroy_connector_work);
			return;
		}
		drm_dp_port_teardown_pdt(port, port->pdt);

@@ -2660,7 +2661,7 @@ static void drm_dp_tx_work(struct work_struct *work)
static void drm_dp_destroy_connector_work(struct work_struct *work)
{
	struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work);
	struct drm_connector *connector;
	struct drm_dp_mst_port *port;

	/*
	 * Not a regular list traverse as we have to drop the destroy
@@ -2669,15 +2670,21 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
	 */
	for (;;) {
		mutex_lock(&mgr->destroy_connector_lock);
		connector = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_connector, destroy_list);
		if (!connector) {
		port = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_dp_mst_port, next);
		if (!port) {
			mutex_unlock(&mgr->destroy_connector_lock);
			break;
		}
		list_del(&connector->destroy_list);
		list_del(&port->next);
		mutex_unlock(&mgr->destroy_connector_lock);

		mgr->cbs->destroy_connector(mgr, connector);
		mgr->cbs->destroy_connector(mgr, port->connector);

		drm_dp_port_teardown_pdt(port, port->pdt);

		if (!port->input && port->vcpi.vcpi > 0)
			drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi);
		kfree(port);
	}
}

+0 −2
Original line number Diff line number Diff line
@@ -743,8 +743,6 @@ struct drm_connector {
	uint8_t num_h_tile, num_v_tile;
	uint8_t tile_h_loc, tile_v_loc;
	uint16_t tile_h_size, tile_v_size;

	struct list_head destroy_list;
};

/**