⬢ DragonFlyBSD Kernel Audit
DF-4469 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/drm_crtc_helper.c
+++ b/sys/dev/drm/drm_crtc_helper.c
@@ -522,6 +522,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set,
 	struct drm_connector *connector;
 	struct drm_connector_list_iter conn_iter;
 	int count = 0, ro, fail = 0;
+	int n_connectors;
 	const struct drm_crtc_helper_funcs *crtc_funcs;
 	struct drm_mode_set save_set;
 	int ret;
@@ -562,10 +563,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set,
 	/*
 	 * Allocate space for the backup of all (non-pointer) encoder and
 	 * connector data.
+	 * DF-4469: the connector list can grow concurrently (DP MST hotplug
+	 * registers connectors under connector_list_lock only), so every walk
+	 * below must be bounded by the snapshot taken here.
 	 */
+	n_connectors = dev->mode_config.num_connector;
 	save_encoder_crtcs = kcalloc(dev->mode_config.num_encoder,
 				sizeof(struct drm_crtc *), GFP_KERNEL);
@@ -587,7 +590,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set,
 	count = 0;
 	drm_connector_list_iter_begin(dev, &conn_iter);
 	drm_for_each_connector_iter(connector, &conn_iter)
-		save_connector_encoders[count++] = connector->encoder;
+		if (count < n_connectors)
+			save_connector_encoders[count++] = connector->encoder;
 	drm_connector_list_iter_end(&conn_iter);
 
@@ -765,7 +769,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set,
 	count = 0;
 	drm_connector_list_iter_begin(dev, &conn_iter);
 	drm_for_each_connector_iter(connector, &conn_iter)
-		connector->encoder = save_connector_encoders[count++];
+		if (count < n_connectors)
+			connector->encoder = save_connector_encoders[count++];
 	drm_connector_list_iter_end(&conn_iter);
 
 	/* after fail drop reference on all unbound connectors in set, let