⬢ DragonFlyBSD Kernel Audit
DF-5059 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/drm_sysctl.c
+++ b/sys/dev/drm/drm_sysctl.c
@@ -265,23 +265,34 @@
 	int retcode;
 	int privcount, i;
 
-	DRM_LOCK(dev);
+	/*
+	 * dev->filelist is protected by dev->filelist_mutex
+	 * (drm_device.h:88), NOT by dev->struct_mutex: drm_open() and
+	 * drm_close() mutate it under filelist_mutex only
+	 * (drm_file.c:514-516, drm_file.c:380-382).  The copy walk below
+	 * is bounded by the list, not by privcount, so opens that land
+	 * between the two walks (e.g. during the M_WAITOK sleep) write
+	 * sizeof(struct drm_file) chunks past tempprivs.  Hold the lock
+	 * the mutators actually take.
+	 */
+	mutex_lock(&dev->filelist_mutex);
 
 	privcount = 0;
 	list_for_each_entry(priv, &dev->filelist, lhead)
 		privcount++;
 
+	/* M_WAITOK under the sleepable filelist_mutex is fine. */
 	tempprivs = kmalloc(sizeof(struct drm_file) * privcount, M_DRM,
 			    M_WAITOK | M_NULLOK);
 	if (tempprivs == NULL) {
-		DRM_UNLOCK(dev);
+		mutex_unlock(&dev->filelist_mutex);
 		return ENOMEM;
 	}
 	i = 0;
 	list_for_each_entry(priv, &dev->filelist, lhead)
 		tempprivs[i++] = *priv;
 
-	DRM_UNLOCK(dev);
+	mutex_unlock(&dev->filelist_mutex);
 
 	DRM_SYSCTL_PRINT(
 	    "\na pid      magic     ioctls\n");