⬢ DragonFlyBSD Kernel Audit
DF-4311 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/video/vga/vga_switcheroo.c
+++ b/sys/dev/video/vga/vga_switcheroo.c
@@ -1020,13 +1020,36 @@
 		break;
 
 	case MOD_UNLOAD:
-	case MOD_SHUTDOWN:
+		/*
+		 * Refuse to unload while clients or a handler are still
+		 * registered: freeing vgasr_priv would leave every
+		 * vga_switcheroo_*() caller (drm_edid.c, i915, amdgpu)
+		 * operating on freed memory (UAF).  Unregister them first.
+		 */
+		if (vgasr_priv->registered_clients > 0 ||
+		    vgasr_priv->handler != NULL) {
+			kprintf("vga_switcheroo: %d client(s)/handler still "
+				"registered, refusing unload\n",
+				vgasr_priv->registered_clients);
+			return (EBUSY);
+		}
 		destroy_dev(vga_switcheroo_dev);
 		kfree(vga_switcheroo_buf, M_VGA_SWITCHEROO_BUF);
+		lockuninit(&vgasr_priv->mux_hw_lk);
 		kfree(vgasr_priv, M_VGA_SWITCHEROO_VGASR_PRIV);
+		vga_switcheroo_buf = NULL;
+		vgasr_priv = NULL;
 		kprintf("vga_switcheroo device unloaded\n");
 		break;
 
+	case MOD_SHUTDOWN:
+		/*
+		 * Keep all state alive at shutdown: DRM drivers may call
+		 * into vga_switcheroo from their own shutdown paths, and
+		 * nothing is gained by freeing it here.
+		 */
+		break;
+
 	default:
 		error = EOPNOTSUPP;
 		break;
--- a/sys/dev/drm/drm_drv.c
+++ b/sys/dev/drm/drm_drv.c
@@ -1144,6 +1144,10 @@
 MODULE_DEPEND(drm, pci, 1, 1, 1);
 MODULE_DEPEND(drm, iicbus, 1, 1, 1);
 
+/* drm_edid.c drm_get_edid_switcheroo() calls vga_switcheroo_lock_ddc()/
+ * vga_switcheroo_unlock_ddc(); drm.ko cannot even link without it. */
+MODULE_DEPEND(drm, vga_switcheroo, 1, 1, 1);
+
 struct dev_ops drm_cdevsw = {
 	{ "drm", 0, D_TRACKCLOSE | D_MPSAFE },
 	.d_open =	drm_open,
--- a/sys/dev/drm/i915/i915_pci.c
+++ b/sys/dev/drm/i915/i915_pci.c
@@ -894,3 +894,7 @@
 #ifdef CONFIG_ACPI
 MODULE_DEPEND(i915, acpi, 1, 1, 1);
 #endif
+
+/* i915_drv.c load path calls vga_switcheroo_handler_flags() and
+ * vga_switcheroo_force_migd() directly (i915_drv.c:741-742). */
+MODULE_DEPEND(i915, vga_switcheroo, 1, 1, 1);
--- a/sys/dev/drm/amd/amdgpu/amdgpu_drv.c
+++ b/sys/dev/drm/amd/amdgpu/amdgpu_drv.c
@@ -1434,4 +1434,8 @@
 #ifdef CONFIG_ACPI
 MODULE_DEPEND(amdgpu, acpi, 1, 1, 1);
 #endif
+
+/* amdgpu_kms.c amdgpu_driver_lastclose_kms() calls
+ * vga_switcheroo_process_delayed_switch() directly. */
+MODULE_DEPEND(amdgpu, vga_switcheroo, 1, 1, 1);
 #endif