NetBSD-Bugs archive

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

kern/48964: In urndis(4), initialization of ifnet structure is not enough, cause panic.



>Number:         48964
>Category:       kern
>Synopsis:       In urndis(4), initialization of ifnet structure is not enough, 
>cause panic.
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Jul 04 18:20:00 +0000 2014
>Originator:     Yasushi Oshima
>Release:        NetBSD-current 6.99.45
>Organization:
>Environment:
NetBSD jaguar 6.99.45 NetBSD 6.99.45 (GENERIC) #3: Sat Jul  5 02:30:41 JST 2014 
 
root@sweety:/export/current/daily/20140705/obj/amd64/sys/arch/amd64/compile/GENERIC
 amd64
>Description:
When running dhcpcd(4) with urndis(4), ioctl(SIOCINITIFADDR) is called and  
kernel panic occurs in ether_ioctl(). 

urndis_ioctl(SIOCINITIFADDR) will pass through to ether_ioctl(),
ether_ioctl(SIOCINITIFADDR) will call ifp->if_init() function.
Howerver, this is NULL, wasn't set when attaching urndis(4).

note:
 This problem appears  with dhcpcd version 6.4.0 (or later?)
 Before 6.4 case, it will call ioctl(SOCSIFFLAGS) in the first. so, 
ifp->if_init() is not called by ether_ioctl().

This problem will exist in netbsd-6, but not appear.
>How-To-Repeat:
On netbsd-current kernel with fix PR kern/48963
and current's dhcpcd ver. 6.4.0 (after 2014.6.16).

1. Attach urndis(4) device
2. Run 'dhcpcd urndis0'
>Fix:
Set urndis_init() to ifp->if_init,
with  change function type void to int (and also add return code)

--- if_urndis.c.old     2014-07-04 19:03:07.000000000 +0900
+++ if_urndis.c 2014-07-05 02:58:13.000000000 +0900
@@ -76,7 +76,7 @@
 static int urndis_rx_list_init(struct urndis_softc *);
 static int urndis_tx_list_init(struct urndis_softc *);
 
-static void urndis_init(struct ifnet *);
+static int urndis_init(struct ifnet *);
 static void urndis_stop(struct ifnet *);
 
 static usbd_status urndis_ctrl_msg(struct urndis_softc *, uint8_t, uint8_t,
@@ -1022,35 +1022,35 @@
 }
 #endif
 
-static void
+static int
 urndis_init(struct ifnet *ifp)
 {
        struct urndis_softc     *sc;
        int                      i, s;
-       usbd_status              err;
+       usbd_status              err=0;
 
        sc = ifp->if_softc;
 
        if (ifp->if_flags & IFF_RUNNING)
-               return;
+               return err;
 
-       if (urndis_ctrl_init(sc) != RNDIS_STATUS_SUCCESS)
-               return;
+       if ((err=urndis_ctrl_init(sc)) != RNDIS_STATUS_SUCCESS)
+               return err;
 
        s = splnet();
 
-       if (urndis_tx_list_init(sc) == ENOBUFS) {
+       if ((err=urndis_tx_list_init(sc)) == ENOBUFS) {
                printf("%s: tx list init failed\n",
                    DEVNAME(sc));
                splx(s);
-               return;
+               return err;
        }
 
-       if (urndis_rx_list_init(sc) == ENOBUFS) {
+       if ((err=urndis_rx_list_init(sc)) == ENOBUFS) {
                printf("%s: rx list init failed\n",
                    DEVNAME(sc));
                splx(s);
-               return;
+               return err;
        }
 
        err = usbd_open_pipe(sc->sc_iface_data, sc->sc_bulkin_no,
@@ -1059,7 +1059,7 @@
                printf("%s: open rx pipe failed: %s\n", DEVNAME(sc),
                    usbd_errstr(err));
                splx(s);
-               return;
+               return err;
        }
 
        err = usbd_open_pipe(sc->sc_iface_data, sc->sc_bulkout_no,
@@ -1068,7 +1068,7 @@
                printf("%s: open tx pipe failed: %s\n", DEVNAME(sc),
                    usbd_errstr(err));
                splx(s);
-               return;
+               return err;
        }
 
        for (i = 0; i < RNDIS_RX_LIST_CNT; i++) {
@@ -1086,6 +1086,7 @@
        ifp->if_flags &= ~IFF_OACTIVE;
 
        splx(s);
+       return err;
 }
 
 static void
@@ -1440,6 +1441,7 @@
        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
        ifp->if_start = urndis_start;
        ifp->if_ioctl = urndis_ioctl;
+       ifp->if_init = urndis_init;
 #if 0
        ifp->if_watchdog = urndis_watchdog;
 #endif



Home | Main Index | Thread Index | Old Index