Module Name: src Committed By: maxv Date: Wed Jan 1 09:05:03 UTC 2020
Modified Files: src/sys/dev/usb: uhid.c Log Message: Fix buffer overflows. Also add missing mutex_exit. To generate a diff of this commit: cvs rdiff -u -r1.110 -r1.111 src/sys/dev/usb/uhid.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/uhid.c diff -u src/sys/dev/usb/uhid.c:1.110 src/sys/dev/usb/uhid.c:1.111 --- src/sys/dev/usb/uhid.c:1.110 Sun Dec 1 12:47:10 2019 +++ src/sys/dev/usb/uhid.c Wed Jan 1 09:05:03 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: uhid.c,v 1.110 2019/12/01 12:47:10 maxv Exp $ */ +/* $NetBSD: uhid.c,v 1.111 2020/01/01 09:05:03 maxv Exp $ */ /* * Copyright (c) 1998, 2004, 2008, 2012 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uhid.c,v 1.110 2019/12/01 12:47:10 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uhid.c,v 1.111 2020/01/01 09:05:03 maxv Exp $"); #ifdef _KERNEL_OPT #include "opt_compat_netbsd.h" @@ -398,6 +398,8 @@ uhid_do_read(struct uhid_softc *sc, stru if (sc->sc_state & UHID_IMMED) { DPRINTFN(1, ("uhidread immed\n")); extra = sc->sc_hdev.sc_report_id != 0; + if (sc->sc_isize + extra > sizeof(buffer)) + return ENOBUFS; err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT, buffer, sc->sc_isize + extra); if (err) @@ -541,8 +543,10 @@ uhid_do_ioctl(struct uhid_softc *sc, u_l case FIOASYNC: mutex_enter(proc_lock); if (*(int *)addr) { - if (sc->sc_async != NULL) + if (sc->sc_async != NULL) { + mutex_exit(proc_lock); return EBUSY; + } sc->sc_async = l->l_proc; DPRINTF(("uhid_do_ioctl: FIOASYNC %p\n", l->l_proc)); } else @@ -589,6 +593,8 @@ uhid_do_ioctl(struct uhid_softc *sc, u_l case USB_SET_IMMED: if (*(int *)addr) { extra = sc->sc_hdev.sc_report_id != 0; + if (sc->sc_isize + extra > sizeof(buffer)) + return ENOBUFS; err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT, buffer, sc->sc_isize + extra); if (err) @@ -615,6 +621,8 @@ uhid_do_ioctl(struct uhid_softc *sc, u_l return EINVAL; } extra = sc->sc_hdev.sc_report_id != 0; + if (size + extra > sizeof(re->ucr_data)) + return ENOBUFS; err = uhidev_get_report(&sc->sc_hdev, re->ucr_report, re->ucr_data, size + extra); if (extra) @@ -638,6 +646,8 @@ uhid_do_ioctl(struct uhid_softc *sc, u_l default: return EINVAL; } + if (size > sizeof(re->ucr_data)) + return ENOBUFS; err = uhidev_set_report(&sc->sc_hdev, re->ucr_report, re->ucr_data, size); if (err)