⬢ DragonFlyBSD Kernel Audit
DF-4543 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/agp/agppriv.h
+++ b/sys/dev/agp/agppriv.h
@@ -89,7 +89,7 @@ void			agp_set_aperture_resource(device_t dev,
 			    int rid);
 int			agp_generic_attach(device_t dev);
 
-void			agp_free_cdev(device_t dev);
+int			agp_free_cdev(device_t dev);
 
 void			agp_free_res(device_t dev);
 int			agp_generic_detach(device_t dev);
--- a/sys/dev/agp/agp.c
+++ b/sys/dev/agp/agp.c
@@ -245,13 +245,27 @@ agp_generic_attach(device_t dev)
 	return 0;
 }
 
+/*
+ * Tear down the userland /dev/agpgart node.
+ *
+ * - Refuse while a client still has the device open: the cdev would
+ *   outlive the softc and si_drv1 would point into freed memory
+ *   (open fds keep their cdev reference across destroy_dev).
+ * - Destroy the node we actually made (minor 0, name "agpgart") via
+ *   the stored as_devnode handle; dev_ops_remove_minor() matches by
+ *   minor, not by device unit, so using device_get_unit() is wrong for
+ *   any unit != 0 and would leave a dangling /dev/agpgart behind.
+ */
 int
-agp_free_cdev(device_t dev)
+agp_free_cdev(device_t dev)
 {
-	dev_ops_remove_minor(&agp_ops, device_get_unit(dev));
+	struct agp_softc *sc = device_get_softc(dev);
+
+	if (sc->as_isopen)
+		return (EBUSY);
+	if (sc->as_devnode != NULL) {
+		destroy_dev(sc->as_devnode);
+		sc->as_devnode = NULL;
+	}
+	return (0);
 }
 
 void
@@ -262,8 +276,11 @@ agp_free_res(device_t dev)
 int
 agp_generic_detach(device_t dev)
 {
-	agp_free_cdev(dev);
+	int error;
+
+	if ((error = agp_free_cdev(dev)) != 0)
+		return (error);
 	agp_free_res(dev);
 	return 0;
 }
--- a/sys/dev/agp/agp_via.c
+++ b/sys/dev/agp/agp_via.c
@@ -223,7 +223,8 @@ agp_via_detach(device_t dev)
 	struct agp_via_softc *sc = device_get_softc(dev);
 
-	agp_free_cdev(dev);
+	if (agp_free_cdev(dev) != 0)
+		return (EBUSY);
 
 	pci_write_config(dev, sc->regs[REG_GARTCTRL], 0, 4);
--- a/sys/dev/agp/agp_sis.c
+++ b/sys/dev/agp/agp_sis.c
@@ -169,7 +169,8 @@ agp_sis_detach(device_t dev)
 	struct agp_sis_softc *sc = device_get_softc(dev);
 
-	agp_free_cdev(dev);
+	if (agp_free_cdev(dev) != 0)
+		return (EBUSY);
 
 	/* Disable the aperture.. */
--- a/sys/dev/agp/agp_amd64.c
+++ b/sys/dev/agp/agp_amd64.c
@@ -248,7 +248,8 @@ agp_amd64_detach(device_t dev)
 	int i;
 
-	agp_free_cdev(dev);
+	if (agp_free_cdev(dev) != 0)
+		return (EBUSY);
 
 	for (i = 0; i < sc->n_mctrl; i++)
--- a/sys/dev/agp/intel-gtt.c
+++ b/sys/dev/agp/intel-gtt.c
@@ -911,7 +911,8 @@ agp_i810_detach(device_t dev)
 	sc = device_get_softc(dev);
-	agp_free_cdev(dev);
+	if (agp_free_cdev(dev) != 0)
+		return (EBUSY);
 
 	/* Clear the GATT base. */