NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/38528: panic on unplugging Apple USB keyboard



>Number:         38528
>Category:       kern
>Synopsis:       panic on unplugging Apple USB keyboard
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Apr 27 11:40:00 +0000 2008
>Originator:     Christoph Egger
>Release:        4.99.61
>Organization:
>Environment:
NetBSD netbsdamd64 4.99.61 NetBSD 4.99.61 (GENERIC) #22: Sun Apr 27 12:17:06 
CEST 2008  
cegger%powermacg5.local@localhost:/Users/cegger/devel/bsd/netbsd/obj.kern.amd64/GENERIC
 amd64

>Description:

A DIAGNOSTIC + DEBUG  kernel panics when unplugging
an Apple USB Keyboard.

It calls KASSERT(false); in src/sys/dev/usb/uhub.c:uhub_childdet(),
line 641.

On the uhub attaches uhidev0 and uhidev1.
Detaching uhidev0, but on detaching uhidev1, dev->subdevs[0] is NULL
in line 634: "for (i = 0; dev->subdevs[i]; i++) {"

Therefore, the loop is not entered and KASSERT(false); is triggered.

A successful tested possible solution is this diff written
by mlelstv:

Index: uhub.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/uhub.c,v
retrieving revision 1.96
diff -u -r1.96 uhub.c
--- uhub.c      21 Apr 2008 23:31:18 -0000      1.96
+++ uhub.c      27 Apr 2008 09:39:14 -0000
@@ -633,7 +633,9 @@
                        continue;
                for (i = 0; dev->subdevs[i]; i++) {
                        if (dev->subdevs[i] == child) {
-                               dev->subdevs[i] = NULL;
+                               do {
+                                       dev->subdevs[i] = dev->subdevs[i+1];
+                               } while (dev->subdevs[++i] != NULL);
                                return;
                        }
                }


However, this triggers another bug in 
src/sys/dev/usb/usb_subr.c:usb_disconnect_port :

config_detach: detached device uhub2 has children uhidev1
panic: config_detach

backtrace:
config_detach+0x388
usb_disconnect_port+0x7d
uhub_explore+0x12b
usb_discover+0x37
usb_event_thread+0x3e

The problem in usb_disconnect_port is 1506:

for (i = 0; dev->subdevs[i]; i++) {

It assumes an 0 terminated list whereby the config_detach()
modifies it. So the assumption is wrong.

A successful tested possible solution is this diff written by
mlelstv:

Index: usb_subr.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/usb_subr.c,v
retrieving revision 1.152
diff -u -r1.152 usb_subr.c
--- usb_subr.c  5 Apr 2008 16:35:35 -0000       1.152
+++ usb_subr.c  27 Apr 2008 10:15:26 -0000
@@ -1503,7 +1503,9 @@
 
        if (dev->subdevs != NULL) {
                DPRINTFN(3,("usb_disconnect_port: disconnect subdevs\n"));
-               for (i = 0; dev->subdevs[i]; i++) {
+               for (i = 0; dev->subdevs[i]; i++)
+                       continue;
+               while (--i >= 0) {
                        printf("%s: at %s", USBDEVPTRNAME(dev->subdevs[i]),
                               hubname);
                        if (up->portno != 0)




>How-To-Repeat:

>Fix:

Use an DIAGNOSTIC+DEBUG kernel and unplug an Apple USB keyboard.



Home | Main Index | Thread Index | Old Index