summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/hid/hid.h8
-rw-r--r--sys/dev/usb/fido.c92
-rw-r--r--sys/dev/usb/files.usb9
-rw-r--r--sys/dev/usb/uhid.c94
-rw-r--r--sys/dev/usb/uhid.h64
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 */