usb/81308: Polling a ugen(4) control endpoint causes a kernel panic

Dirk Gouders gouder at et.bocholt.gh-ge.de
Fri May 20 15:00:26 GMT 2005


>Number:         81308
>Category:       usb
>Synopsis:       Polling a ugen(4) control endpoint causes a kernel panic
>Confidential:   no
>Severity:       critical
>Priority:       medium
>Responsible:    freebsd-usb
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri May 20 15:00:24 GMT 2005
>Closed-Date:
>Last-Modified:
>Originator:     Dirk Gouders
>Release:        FreeBSD 4.11-STABLE i386
>Organization:
FH Gelsenkirchen, Abt. Bocholt
>Environment:
System: FreeBSD karga.hank.home 4.11-STABLE FreeBSD 4.11-STABLE #4: Fri May 20 16:01:10 CEST 2005 root at karga.hank.home:/usr/src/sys/compile/KARGA i386


	
>Description:
	Polling a ugen control endpoint (ugen0) causes a page fault in the
    function ugenpoll().
>How-To-Repeat:
	When a USB device that is handled by ugen(4) is attached, the
    following program invoked with the argument /dev/ugen0 will
    reproduce the kernel panic. 

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <poll.h>
#include <errno.h>

int main(int argc, char *argv[])
{
    int fd;
    int nfd;
    char *path = argv[1];
    struct pollfd pfd[1];
    
    fd = open(path, O_RDWR);
    if ( fd < 0 ) {
        fprintf(stderr, "%s: %s\n", path, strerror(errno));
        exit(1);
    }
    pfd[0].fd = fd;
    pfd[0].events = POLLHUP;
    pfd[0].revents = 0;
    nfd = poll(pfd, 1, 10);
    if ( nfd < 0 ) {
        fprintf(stderr, "poll(2): %s\n", strerror(errno));
        exit(1);
    }
    if ( pfd[0].revents && POLLNVAL )
        printf("POLLNVAL set in revents\n");
    printf("nfd = %d\n", nfd);
    
    close(fd);
    exit(0);
}


>Fix:

	I reported this problem to freebsd-hackers and Hans Petter Selasky
    noted that the control endpoint does not support polling and
    suggested that /sys/dev/usb/ugen.c should handle such a situation.

	The attached patch works for me, although I am not sure if this
    is the most elegant solution.

    On a machine running 5.4-RELEASE, this problem does not occur
	(poll() just returns '0') and I could not see any changes in
    /sys/dev/usb/ugen.c that addresses this problem.

--- ugen.c.diff begins here ---
--- /sys/dev/usb/ugen.c.orig	Tue Apr 26 09:44:44 2005
+++ /sys/dev/usb/ugen.c	Fri May 20 16:26:39 2005
@@ -1421,6 +1421,10 @@
 	int revents = 0;
 	int s;
 
+	/* Do not allow to poll a control endpoint */
+	if ( UGENENDPOINT(dev) == USB_CONTROL_ENDPOINT )
+		return POLLNVAL;
+	
 	USB_GET_SC(ugen, UGENUNIT(dev), sc);
 
 	if (sc->sc_dying)
--- ugen.c.diff ends here ---


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-usb mailing list