Subject: kern/33352: poll on control endpoint of ugen device crashes
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <cg2v@andrew.cmu.edu>
List: netbsd-bugs
Date: 04/24/2006 18:05:01
>Number: 33352
>Category: kern
>Synopsis: poll on control endpoint of ugen device crashes
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Mon Apr 24 18:05:00 +0000 2006
>Originator: Chaskiel Grundman
>Release: 3.0
>Organization:
>Environment:
NetBSD sanmartin.squill.dementia.org 3.0 NetBSD 3.0 (GENERIC) #0: Sun Dec 18 21:51:37 UTC 2005 builds@works.netbsd.org:/home/builds/ab/netbsd-3-0-RELEASE/amd64/200512182024Z-obj/home/builds/ab/netbsd-3-0-RELEASE/src/sys/arch/amd64/compile/GENERIC amd64
>Description:
The openct smart card resource manager (http://www.opensc-project.org/openct/) uses ugen to communicate with usb smartcard devices on *BSD. When configured to detect device disconnects, it poll(2)'s the device with POLLHUP (this apparently works on linux).
On NetBSD 3.0, this causes a crash in ugenpoll. a DIAGNOSTIC kernel printf's the following error: ugenpoll: no edesc
>How-To-Repeat:
1) acquire a cryptoflex egate token
2) install openct
3) launch a hotplug-enabled ifdhandler (ifdhandler -FD egate /dev/ugen0.00)
4) boom.
I presume that this could be replicated with any usb device that used ugen, but it would involve writing code.
>Fix:
I have not tested it yet, but the following patch (modeled after ugenread/ugenwrite) should prevent the crash
Index: ugen.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/ugen.c,v
retrieving revision 1.71
diff -u -r1.71 ugen.c
--- ugen.c 2 Mar 2005 11:37:27 -0000 1.71
+++ ugen.c 24 Apr 2006 17:55:51 -0000
@@ -1331,6 +1331,7 @@
int
ugenpoll(dev_t dev, int events, usb_proc_ptr p)
{
+ int endpt = UGENENDPOINT(dev);
struct ugen_softc *sc;
struct ugen_endpoint *sce;
int revents = 0;
@@ -1341,6 +1342,9 @@
if (sc->sc_dying)
return (EIO);
+ if (endpt == USB_CONTROL_ENDPOINT)
+ return (ENODEV);
+
/* XXX always IN */
sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
if (sce == NULL)