Fix a double free in uhidev_close() caused by a race between
authoranton <anton@openbsd.org>
Wed, 17 Nov 2021 06:20:30 +0000 (06:20 +0000)
committeranton <anton@openbsd.org>
Wed, 17 Nov 2021 06:20:30 +0000 (06:20 +0000)
uhidev_open() and uhidev_close(). In uhidev_close() the UHIDEV_OPEN flag
is cleared early on but the same thread can end up sleeping while
closing the input or output pipe. This allows another thread to enter
uhidev_open() but only to fail opening either the input or output pipe
since they are already open for exclusive use. The uhidev_open() error
path frees the input buffer but leaves a dangling pointer around;
causing uhidev_close() to free the same buffer.

This can at least happen on xhci(4) which can end up sleeping in
xhci_pipe_close().

Reported by and ok gnezdo@

sys/dev/usb/uhidev.c

index b50d438..3e61642 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uhidev.c,v 1.100 2021/11/15 15:36:24 anton Exp $      */
+/*     $OpenBSD: uhidev.c,v 1.101 2021/11/17 06:20:30 anton Exp $      */
 /*     $NetBSD: uhidev.c,v 1.14 2003/03/11 16:44:00 augustss Exp $     */
 
 /*
@@ -592,6 +592,7 @@ out2:
 out1:
        DPRINTF(("uhidev_open: failed in someway"));
        free(sc->sc_ibuf, M_USBDEV, sc->sc_isize);
+       sc->sc_ibuf = NULL;
        scd->sc_state &= ~UHIDEV_OPEN;
        sc->sc_refcnt = 0;
        sc->sc_ipipe = NULL;