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)