Module Name:    src
Committed By:   riastradh
Date:           Tue Sep  7 10:44:05 UTC 2021

Modified Files:
        src/sys/dev/usb: ugen.c

Log Message:
ugen(4): Keep fields null when not allocated; kassert on close.

This avoids silent leaks in DIAGNOSTIC kernels.


To generate a diff of this commit:
cvs rdiff -u -r1.166 -r1.167 src/sys/dev/usb/ugen.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/usb/ugen.c
diff -u src/sys/dev/usb/ugen.c:1.166 src/sys/dev/usb/ugen.c:1.167
--- src/sys/dev/usb/ugen.c:1.166	Tue Sep  7 10:43:51 2021
+++ src/sys/dev/usb/ugen.c	Tue Sep  7 10:44:04 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: ugen.c,v 1.166 2021/09/07 10:43:51 riastradh Exp $	*/
+/*	$NetBSD: ugen.c,v 1.167 2021/09/07 10:44:04 riastradh Exp $	*/
 
 /*
  * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
 
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ugen.c,v 1.166 2021/09/07 10:43:51 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ugen.c,v 1.167 2021/09/07 10:44:04 riastradh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_compat_netbsd.h"
@@ -669,8 +669,10 @@ ugenopen(dev_t dev, int flag, int mode, 
 			DPRINTFN(5, ("ugenopen: isoc open done\n"));
 			break;
 		bad:
-			while (--i >= 0) /* implicit buffer free */
+			while (--i >= 0) { /* implicit buffer free */
 				usbd_destroy_xfer(sce->isoreqs[i].xfer);
+				sce->isoreqs[i].xfer = NULL;
+			}
 			usbd_close_pipe(sce->pipeh);
 			sce->pipeh = NULL;
 			kmem_free(sce->ibuf, isize * UGEN_NISOFRAMES);
@@ -699,13 +701,8 @@ ugen_do_close(struct ugen_softc *sc, int
 
 	KASSERT(KERNEL_LOCKED_P()); /* sc_is_open */
 
-	if (!sc->sc_is_open[endpt]) {
-		KASSERT(sc->sc_endpoints[endpt][IN].pipeh == NULL);
-		KASSERT(sc->sc_endpoints[endpt][OUT].pipeh == NULL);
-		KASSERT(sc->sc_endpoints[endpt][IN].ibuf == NULL);
-		KASSERT(sc->sc_endpoints[endpt][OUT].ibuf == NULL);
-		return;
-	}
+	if (!sc->sc_is_open[endpt])
+		goto out;
 
 	if (endpt == USB_CONTROL_ENDPOINT) {
 		DPRINTFN(5, ("ugenclose: close control\n"));
@@ -733,13 +730,16 @@ ugen_do_close(struct ugen_softc *sc, int
 			msize = isize;
 			break;
 		case UE_ISOCHRONOUS:
-			for (i = 0; i < UGEN_NISOREQS; ++i)
+			for (i = 0; i < UGEN_NISOREQS; ++i) {
 				usbd_destroy_xfer(sce->isoreqs[i].xfer);
+				sce->isoreqs[i].xfer = NULL;
+			}
 			msize = isize * UGEN_NISOFRAMES;
 			break;
 		case UE_BULK:
 			if (sce->state & (UGEN_BULK_RA | UGEN_BULK_WB)) {
 				usbd_destroy_xfer(sce->ra_wb_xfer);
+				sce->ra_wb_xfer = NULL;
 				msize = sce->ra_wb_bufsize;
 			}
 			break;
@@ -755,6 +755,14 @@ ugen_do_close(struct ugen_softc *sc, int
 	}
 
 out:	sc->sc_is_open[endpt] = 0;
+	for (dir = OUT; dir <= IN; dir++) {
+		sce = &sc->sc_endpoints[endpt][dir];
+		KASSERT(sce->pipeh == NULL);
+		KASSERT(sce->ibuf == NULL);
+		KASSERT(sce->ra_wb_xfer == NULL);
+		for (i = 0; i < UGEN_NISOREQS; i++)
+			KASSERT(sce->isoreqs[i].xfer == NULL);
+	}
 }
 
 static int
@@ -1649,6 +1657,8 @@ ugen_do_ioctl(struct ugen_softc *sc, int
 			/* Only turn RA on if it's currently off. */
 			if (sce->state & UGEN_BULK_RA)
 				return 0;
+			KASSERT(sce->ra_wb_xfer == NULL);
+			KASSERT(sce->ibuf == NULL);
 
 			if (sce->ra_wb_bufsize == 0 || sce->ra_wb_reqsize == 0)
 				/* shouldn't happen */
@@ -1674,6 +1684,7 @@ ugen_do_ioctl(struct ugen_softc *sc, int
 				kmem_free(sce->ibuf, sce->ra_wb_bufsize);
 				sce->ibuf = NULL;
 				usbd_destroy_xfer(sce->ra_wb_xfer);
+				sce->ra_wb_xfer = NULL;
 				return EIO;
 			}
 		} else {
@@ -1684,6 +1695,7 @@ ugen_do_ioctl(struct ugen_softc *sc, int
 			sce->state &= ~UGEN_BULK_RA;
 			usbd_abort_pipe(sce->pipeh);
 			usbd_destroy_xfer(sce->ra_wb_xfer);
+			sce->ra_wb_xfer = NULL;
 			/*
 			 * XXX Discard whatever's in the buffer, but we
 			 * should keep it around and drain the buffer
@@ -1707,12 +1719,15 @@ ugen_do_ioctl(struct ugen_softc *sc, int
 			/* Only turn WB on if it's currently off. */
 			if (sce->state & UGEN_BULK_WB)
 				return 0;
+			KASSERT(sce->ra_wb_xfer == NULL);
+			KASSERT(sce->ibuf == NULL);
 
 			if (sce->ra_wb_bufsize == 0 || sce->ra_wb_reqsize == 0)
 				/* shouldn't happen */
 				return EINVAL;
 			error = usbd_create_xfer(sce->pipeh, sce->ra_wb_reqsize,
 			    0, 0, &sce->ra_wb_xfer);
+			/* XXX check error???  */
 			sce->ra_wb_xferlen = sce->ra_wb_reqsize;
 			sce->ibuf = kmem_alloc(sce->ra_wb_bufsize, KM_SLEEP);
 			sce->fill = sce->cur = sce->ibuf;
@@ -1732,6 +1747,7 @@ ugen_do_ioctl(struct ugen_softc *sc, int
 			 */
 			usbd_abort_pipe(sce->pipeh);
 			usbd_destroy_xfer(sce->ra_wb_xfer);
+			sce->ra_wb_xfer = NULL;
 			kmem_free(sce->ibuf, sce->ra_wb_bufsize);
 			sce->ibuf = NULL;
 		}

Reply via email to