Module Name: src
Committed By: riastradh
Date: Mon Jun 14 18:44:53 UTC 2021
Modified Files:
src/sys/dev/pad: pad.c
Log Message:
pad(4): Explain what's wrong with using device pointers like this.
...and why the kernel lock is not enough.
To generate a diff of this commit:
cvs rdiff -u -r1.74 -r1.75 src/sys/dev/pad/pad.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/pad/pad.c
diff -u src/sys/dev/pad/pad.c:1.74 src/sys/dev/pad/pad.c:1.75
--- src/sys/dev/pad/pad.c:1.74 Mon Jun 14 18:44:45 2021
+++ src/sys/dev/pad/pad.c Mon Jun 14 18:44:53 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: pad.c,v 1.74 2021/06/14 18:44:45 riastradh Exp $ */
+/* $NetBSD: pad.c,v 1.75 2021/06/14 18:44:53 riastradh Exp $ */
/*-
* Copyright (c) 2007 Jared D. McNeill <[email protected]>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.74 2021/06/14 18:44:45 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.75 2021/06/14 18:44:53 riastradh Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -386,6 +386,36 @@ pad_close(struct pad_softc *sc)
device_t self = sc->sc_dev;
cfdata_t cf = device_cfdata(self);
+ /*
+ * XXX This is not quite enough to prevent racing with drvctl
+ * detach. What can happen:
+ *
+ * cpu0 cpu1
+ *
+ * pad_close
+ * take kernel lock
+ * sc->sc_open = 0
+ * drop kernel lock
+ * wait for config_misc_lock
+ * drvctl detach
+ * take kernel lock
+ * drop kernel lock
+ * wait for config_misc_lock
+ * retake kernel lock
+ * drop config_misc_lock
+ * take config_misc_lock
+ * wait for kernel lock
+ * pad_detach (sc_open=0 already)
+ * free device
+ * drop kernel lock
+ * use device after free
+ *
+ * We need a way to grab a reference to the device so it won't
+ * be freed until we're done -- it's OK if we config_detach
+ * twice as long as it's idempotent, but not OK if the first
+ * config_detach frees the struct device before the second one
+ * has finished handling it.
+ */
KERNEL_LOCK(1, NULL);
KASSERT(sc->sc_open);
sc->sc_open = 0;