⬢ DragonFlyBSD Kernel Audit
DF-4378 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/drm_drv.c
+++ b/sys/dev/drm/drm_drv.c
@@ -26,6 +26,8 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
+#include <sys/conf.h>	/* destroy_dev() for drm_minor_free() */
+
 #include <linux/debugfs.h>
 #include <linux/fs.h>
 #include <linux/module.h>
@@ -183,9 +185,18 @@
 	if (!minor)
 		return;
 
-#if 0
-	put_device(minor->kdev);
-#endif
+/*
+	 * DF-4378: on DragonFly drm_sysfs_minor_alloc() kzalloc()s the
+	 * struct device and make_dev()s the "dri/cardN" cdev. Release both
+	 * here or every driver attach/detach cycle leaks them and leaves a
+	 * stale /dev/dri node with si_drv1 dangling at the freed drm_device.
+	 */
+	if (minor->devnode != NULL) {
+		destroy_dev(minor->devnode);
+		minor->devnode = NULL;
+	}
+	if (minor->kdev != NULL)
+		kfree(minor->kdev);
 
 	spin_lock_irqsave(&drm_minor_lock, flags);
 	idr_remove(&drm_minors_idr, minor->index);
--- a/sys/dev/drm/include/drm/drm_file.h
+++ b/sys/dev/drm/include/drm/drm_file.h
@@ -78,6 +78,7 @@
 	int index;			/* Minor device number */
 	int type;                       /* Control or render */
 	struct device *kdev;		/* Linux device */
+	struct cdev *devnode;		/* DF: devfs cdev from make_dev() */
 	struct drm_device *dev;
 
 	struct dentry *debugfs_root;
--- a/sys/dev/drm/drm_sysfs.c
+++ b/sys/dev/drm/drm_sysfs.c
@@ -97,6 +97,8 @@
 	devnode = make_dev(&drm_cdevsw, minor->index,
 		DRM_DEV_UID, DRM_DEV_GID, DRM_DEV_MODE, "dri/%s", dev_str);
 
+	minor->devnode = devnode;	/* DF-4378: so drm_minor_free can destroy it */
+
 	kdev->parent = minor->dev->dev;
 	dev_set_drvdata(kdev, minor);