diff options
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/hid/hid.h | 8 | ||||
-rw-r--r-- | sys/dev/usb/fido.c | 92 | ||||
-rw-r--r-- | sys/dev/usb/files.usb | 9 | ||||
-rw-r--r-- | sys/dev/usb/uhid.c | 94 | ||||
-rw-r--r-- | sys/dev/usb/uhid.h | 64 |
5 files changed, 223 insertions, 44 deletions
diff --git a/sys/dev/hid/hid.h b/sys/dev/hid/hid.h index ea033b13887..17de4065e0c 100644 --- a/sys/dev/hid/hid.h +++ b/sys/dev/hid/hid.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hid.h,v 1.5 2016/09/12 09:10:05 mpi Exp $ */ +/* $OpenBSD: hid.h,v 1.6 2019/12/17 13:08:54 reyk Exp $ */ /* $NetBSD: hid.h,v 1.8 2002/07/11 21:14:25 augustss Exp $ */ /* $FreeBSD: src/sys/dev/usb/hid.h,v 1.7 1999/11/17 22:33:40 n_hibma Exp $ */ @@ -124,6 +124,7 @@ int hid_is_collection(const void *, int, uint8_t, int32_t); #define HUP_CAMERA_CONTROL 0x0090 #define HUP_ARCADE 0x0091 #define HUP_VENDOR 0x00ff +#define HUP_FIDO 0xf1d0 #define HUP_MICROSOFT 0xff00 /* XXX compat */ #define HUP_APPLE 0x00ff @@ -397,6 +398,11 @@ int hid_is_collection(const void *, int, uint8_t, int32_t); /* Usages, Consumer */ #define HUC_AC_PAN 0x0238 +/* Usages, FIDO */ +#define HUF_U2FHID 0x0001 +#define HUF_RAW_IN_DATA_REPORT 0x0020 +#define HUF_RAW_OUT_DATA_REPORT 0x0021 + #define HID_USAGE2(p, u) (((p) << 16) | u) #define HID_GET_USAGE(u) ((u) & 0xffff) #define HID_GET_USAGE_PAGE(u) (((u) >> 16) & 0xffff) diff --git a/sys/dev/usb/fido.c b/sys/dev/usb/fido.c new file mode 100644 index 00000000000..5d68cff520e --- /dev/null +++ b/sys/dev/usb/fido.c @@ -0,0 +1,92 @@ +/* $OpenBSD: fido.c,v 1.1 2019/12/17 13:08:54 reyk Exp $ */ + +/* + * Copyright (c) 2019 Reyk Floeter <reyk@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/tty.h> +#include <sys/conf.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbhid.h> +#include <dev/usb/usbdevs.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usbdi_util.h> + +#include <dev/usb/uhidev.h> +#include <dev/usb/uhid.h> + +int fido_match(struct device *, void *, void *); + +struct cfdriver fido_cd = { + NULL, "fido", DV_DULL +}; + +const struct cfattach fido_ca = { + sizeof(struct uhid_softc), + fido_match, + uhid_attach, + uhid_detach, +}; + +int +fido_match(struct device *parent, void *match, void *aux) +{ + struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; + int size; + void *desc; + int ret = UMATCH_NONE; + + if (uha->reportid == UHIDEV_CLAIM_ALLREPORTID) + return (ret); + + /* Find the FIDO usage page and U2F collection */ + uhidev_get_report_desc(uha->parent, &desc, &size); + if (hid_is_collection(desc, size, uha->reportid, + HID_USAGE2(HUP_FIDO, HUF_U2FHID))) + ret = UMATCH_IFACECLASS; + + return (ret); +} + +int +fidoopen(dev_t dev, int flag, int mode, struct proc *p) +{ + return (uhid_do_open(dev, flag, mode, p)); +} + +int +fidoioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) +{ + int error; + + switch (cmd) { + case FIONBIO: + case FIOASYNC: + case USB_GET_DEVICEINFO: + break; + default: + /* + * Users don't need USB/HID ioctl access to fido(4) devices + * but it can still be useful for debugging by root. + */ + if ((error = suser(p)) != 0) + return (error); + break; + } + + return (uhidioctl(dev, cmd, addr, flag, p)); +} diff --git a/sys/dev/usb/files.usb b/sys/dev/usb/files.usb index 2a68642a9a9..0f697127e92 100644 --- a/sys/dev/usb/files.usb +++ b/sys/dev/usb/files.usb @@ -1,4 +1,4 @@ -# $OpenBSD: files.usb,v 1.140 2019/07/09 05:43:03 kevlo Exp $ +# $OpenBSD: files.usb,v 1.141 2019/12/17 13:08:54 reyk Exp $ # $NetBSD: files.usb,v 1.16 2000/02/14 20:29:54 augustss Exp $ # # Config file and device description for machine-independent USB code. @@ -74,7 +74,12 @@ file dev/usb/uhidev.c uhidev # Generic HID devices device uhid: hid attach uhid at uhidbus -file dev/usb/uhid.c uhid needs-flag +file dev/usb/uhid.c uhid | fido needs-flag + +# FIDO/U2F security keys +device fido: hid +attach fido at uhidbus +file dev/usb/fido.c fido needs-flag # Keyboards file dev/usb/ukbdmap.c hidkbd diff --git a/sys/dev/usb/uhid.c b/sys/dev/usb/uhid.c index 28faca5d82d..7cc74837a88 100644 --- a/sys/dev/usb/uhid.c +++ b/sys/dev/usb/uhid.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uhid.c,v 1.72 2019/11/27 11:16:59 mpi Exp $ */ +/* $OpenBSD: uhid.c,v 1.73 2019/12/17 13:08:54 reyk Exp $ */ /* $NetBSD: uhid.c,v 1.57 2003/03/11 16:44:00 augustss Exp $ */ /* @@ -35,6 +35,8 @@ * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf */ +#include "fido.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> @@ -57,6 +59,7 @@ #include <dev/usb/usbdi_util.h> #include <dev/usb/uhidev.h> +#include <dev/usb/uhid.h> #ifdef UHID_DEBUG #define DPRINTF(x) do { if (uhiddebug) printf x; } while (0) @@ -67,33 +70,7 @@ int uhiddebug = 0; #define DPRINTFN(n,x) #endif -struct uhid_softc { - struct uhidev sc_hdev; - - u_char *sc_obuf; - - struct clist sc_q; - struct selinfo sc_rsel; - u_char sc_state; /* driver state */ -#define UHID_ASLP 0x01 /* waiting for device data */ - - int sc_refcnt; -}; - -#define UHIDUNIT(dev) (minor(dev)) -#define UHID_CHUNK 128 /* chunk size for read */ -#define UHID_BSIZE 1020 /* buffer size */ - -void uhid_intr(struct uhidev *, void *, u_int len); - -int uhid_do_read(struct uhid_softc *, struct uio *uio, int); -int uhid_do_write(struct uhid_softc *, struct uio *uio, int); -int uhid_do_ioctl(struct uhid_softc*, u_long, caddr_t, int, - struct proc *); - -int uhid_match(struct device *, void *, void *); -void uhid_attach(struct device *, struct device *, void *); -int uhid_detach(struct device *, int); +int uhid_match(struct device *, void *, void *); struct cfdriver uhid_cd = { NULL, "uhid", DV_DULL @@ -106,6 +83,28 @@ const struct cfattach uhid_ca = { uhid_detach, }; +struct uhid_softc * +uhid_lookup(dev_t dev) +{ + struct uhid_softc *sc = NULL; + struct cdevsw *cdev; + struct cfdriver *cd; + + cdev = &cdevsw[major(dev)]; + if (cdev->d_open == uhidopen) + cd = &uhid_cd; +#if NFIDO > 0 + else if (cdev->d_open == fidoopen) + cd = &fido_cd; +#endif + else + return (NULL); + if (UHIDUNIT(dev) < cd->cd_ndevs) + sc = cd->cd_devs[UHIDUNIT(dev)]; + + return (sc); +} + int uhid_match(struct device *parent, void *match, void *aux) { @@ -201,13 +200,16 @@ uhid_intr(struct uhidev *addr, void *data, u_int len) int uhidopen(dev_t dev, int flag, int mode, struct proc *p) { + return (uhid_do_open(dev, flag, mode, p)); +} + +int +uhid_do_open(dev_t dev, int flag, int mode, struct proc *p) +{ struct uhid_softc *sc; int error; - if (UHIDUNIT(dev) >= uhid_cd.cd_ndevs) - return (ENXIO); - sc = uhid_cd.cd_devs[UHIDUNIT(dev)]; - if (sc == NULL) + if ((sc = uhid_lookup(dev)) == NULL) return (ENXIO); DPRINTF(("uhidopen: sc=%p\n", sc)); @@ -231,7 +233,8 @@ uhidclose(dev_t dev, int flag, int mode, struct proc *p) { struct uhid_softc *sc; - sc = uhid_cd.cd_devs[UHIDUNIT(dev)]; + if ((sc = uhid_lookup(dev)) == NULL) + return (ENXIO); DPRINTF(("uhidclose: sc=%p\n", sc)); @@ -295,7 +298,8 @@ uhidread(dev_t dev, struct uio *uio, int flag) struct uhid_softc *sc; int error; - sc = uhid_cd.cd_devs[UHIDUNIT(dev)]; + if ((sc = uhid_lookup(dev)) == NULL) + return (ENXIO); sc->sc_refcnt++; error = uhid_do_read(sc, uio, flag); @@ -317,9 +321,13 @@ uhid_do_write(struct uhid_softc *sc, struct uio *uio, int flag) size = sc->sc_hdev.sc_osize; error = 0; - if (uio->uio_resid != size) - return (EINVAL); - error = uiomove(sc->sc_obuf, size, uio); + if (uio->uio_resid > size) + return (EMSGSIZE); + else if (uio->uio_resid < size) { + /* don't leak kernel memory to the USB device */ + memset(sc->sc_obuf + uio->uio_resid, 0, size - uio->uio_resid); + } + error = uiomove(sc->sc_obuf, uio->uio_resid, uio); if (!error) { if (uhidev_set_report(sc->sc_hdev.sc_parent, UHID_OUTPUT_REPORT, sc->sc_hdev.sc_report_id, sc->sc_obuf, @@ -336,7 +344,8 @@ uhidwrite(dev_t dev, struct uio *uio, int flag) struct uhid_softc *sc; int error; - sc = uhid_cd.cd_devs[UHIDUNIT(dev)]; + if ((sc = uhid_lookup(dev)) == NULL) + return (ENXIO); sc->sc_refcnt++; error = uhid_do_write(sc, uio, flag); @@ -386,7 +395,8 @@ uhidioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) struct uhid_softc *sc; int error; - sc = uhid_cd.cd_devs[UHIDUNIT(dev)]; + if ((sc = uhid_lookup(dev)) == NULL) + return (ENXIO); sc->sc_refcnt++; error = uhid_do_ioctl(sc, cmd, addr, flag, p); @@ -402,7 +412,8 @@ uhidpoll(dev_t dev, int events, struct proc *p) int revents = 0; int s; - sc = uhid_cd.cd_devs[UHIDUNIT(dev)]; + if ((sc = uhid_lookup(dev)) == NULL) + return (ENXIO); if (usbd_is_dying(sc->sc_hdev.sc_udev)) return (POLLERR); @@ -458,7 +469,8 @@ uhidkqfilter(dev_t dev, struct knote *kn) struct klist *klist; int s; - sc = uhid_cd.cd_devs[UHIDUNIT(dev)]; + if ((sc = uhid_lookup(dev)) == NULL) + return (ENXIO); if (usbd_is_dying(sc->sc_hdev.sc_udev)) return (EIO); diff --git a/sys/dev/usb/uhid.h b/sys/dev/usb/uhid.h new file mode 100644 index 00000000000..9b46dfc344f --- /dev/null +++ b/sys/dev/usb/uhid.h @@ -0,0 +1,64 @@ +/* $OpenBSD: uhid.h,v 1.1 2019/12/17 13:08:54 reyk Exp $ */ +/* $NetBSD: uhid.c,v 1.57 2003/03/11 16:44:00 augustss Exp $ */ + +/* + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Lennart Augustsson (lennart@augustsson.net) at + * Carlstedt Research & Technology. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef _KERNEL + +struct uhid_softc { + struct uhidev sc_hdev; + + u_char *sc_obuf; + + struct clist sc_q; + struct selinfo sc_rsel; + u_char sc_state; /* driver state */ +#define UHID_ASLP 0x01 /* waiting for device data */ + + int sc_refcnt; +}; + +extern struct cfdriver uhid_cd; +extern struct cfdriver fido_cd; + +#define UHIDUNIT(dev) (minor(dev)) +#define UHID_CHUNK 128 /* chunk size for read */ +#define UHID_BSIZE 1020 /* buffer size */ + +void uhid_intr(struct uhidev *, void *, u_int); +struct uhid_softc *uhid_lookup(dev_t); + +int uhid_do_open(dev_t, int, int, struct proc *); + +void uhid_attach(struct device *, struct device *, void *); +int uhid_detach(struct device *, int); + +#endif /* _KERNEL */ |