⬢ DragonFlyBSD Kernel Audit
DF-5149 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/misc/pps/pps.c
+++ b/sys/dev/misc/pps/pps.c
@@ -36,6 +36,7 @@
 	int	pps_open;
 	struct	ppb_device pps_dev;	
 	struct	pps_state pps;
+	cdev_t	pps_cdev;
 
 	struct resource *intr_resource;	/* interrupt resource */
 	void *intr_cookie;		/* interrupt registration cookie */
@@ -55,6 +56,7 @@
 static	d_open_t	ppsopen;
 static	d_close_t	ppsclose;
 static	d_ioctl_t	ppsioctl;
+static int		ppsdetach(device_t);
 
 static struct dev_ops pps_ops = {
 	{ PPS_NAME, 0, 0 },
@@ -100,8 +102,26 @@
 		return (ENXIO);
 
 	unit = device_get_unit(ppsdev);
-	make_dev(&pps_ops, unit, UID_ROOT, GID_WHEEL,
-		 0644, PPS_NAME "%d", unit);
+	sc->pps_cdev = make_dev(&pps_ops, unit, UID_ROOT, GID_WHEEL,
+				0644, PPS_NAME "%d", unit);
+	return (0);
+}
+
+static int
+ppsdetach(device_t ppsdev)
+{
+	struct pps_data *sc = DEVTOSOFTC(ppsdev);
+
+	/*
+	 * Refuse to detach while a client has us open: ppsopen() owns the
+	 * ppbus and a registered interrupt handler at that point
+	 * (pps.c:118-133), and ppb_release_bus() is the only thing that
+	 * tears that registration down (ppbconf.c:514-521).
+	 */
+	if (sc->pps_open)
+		return (EBUSY);
+	if (sc->pps_cdev != NULL)
+		destroy_dev(sc->pps_cdev);
 	return (0);
 }
 
@@ -192,6 +212,7 @@
 	DEVMETHOD(device_identify,	bus_generic_identify),
 	DEVMETHOD(device_probe,		ppsprobe),
 	DEVMETHOD(device_attach,	ppsattach),
+	DEVMETHOD(device_detach,	ppsdetach),
 
 	DEVMETHOD_END
 };