Subject: kern/27678: destroying if_wm.c vlans with ifconfig can crash system
To: None <gnats-bugs@gnats.NetBSD.org>
From: None <chuck@ece.cmu.edu>
List: netbsd-bugs
Date: 10/29/2004 22:35:55
>Number:         27678
>Category:       kern
>Synopsis:       destroying if_wm.c vlans with ifconfig can crash system
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Oct 30 02:38:00 UTC 2004
>Closed-Date:
>Last-Modified:
>Originator:     Chuck Cranor
>Release:        NetBSD 2.0_RC4
>Organization:
Carnegie Mellon University
>Environment:
System: NetBSD bum.pdl.cmu.edu 2.0_RC4 NetBSD 2.0_RC4 (GENERIC) #5: Thu Oct 28 22:03:22 UTC 2004  isildur@bum.pdl.cmu.edu:/home/netbsd/20/src/sys/arch/i386/compile/GENERIC i386
Architecture: i386
Machine: i386
>Description:

	we have a 2.0_RC4 system with a wm0 ethernet interface that is 
	connected to a switch with 2 vlans (vlan0, vlan1).   the wm0 
	interface is configured as "up" in /etc/rc.conf, and the vlan0
	and vlan1 interfaces are configured using /etc/ifconfig.vlan{0,1}.

	with this config, running "/etc/rc.d/network stop" crashes the 
	system.   this is because the script does "ifconfig wm0 down"
	before unconfiguring the vlan interfaces.

	when the script attempts to "ifconfig <vlan> destroy" the final
	vlan associated with wm0 (which is already shut down), the following
	call stack occurs:

        if_clone_destroy 
          -> vlan_clone_destroy 
            -> vlan_unconfig 
              -> vlan_ether_purgemulti
                -> wm_ioctl   /* command == SIOCDELMULTI */

	wm_ioctl() has the following code:

               error = ether_ioctl(ifp, cmd, data);
                if (error == ENETRESET) {
                        /*
                         * Multicast list has changed; set the hardware filter
                         * accordingly.
                         */
                        wm_set_filter(sc);
                        error = 0;
                }

	
	this code results in 'wm_set_filter(sc)' for wm0 getting called,
	even though the wm0 interface is already down (!RUNNING).

	unfortunately, the wm_set_filter() call enables receive interrupts 
	on wm0 even though the interface is down.   when the first receive 
	interrupt occurs, it tries to do mbuf operations without having
	any receive ring allocated (again, because the interface is supposed 
	to be down).   

	this results in a reference though a NULL mbuf pointer and a 
	kernel panic.
	
>How-To-Repeat:

	configure up a wm0, vlan0, vlan1.   running the following commands
	(this is what '/etc/rc.d/network stop' does):

		ifconfig wm0 down
		ifconfig wm0 destroy
		ifconfig vlan1 down
		ifconfig vlan1 destroy
		ifconfig vlan0 down
		ifconfig vlan0 destroy

	the system will panic after the final destroy command as soon
	as a receive interrupt occurs.

>Fix:

	do not call wm_set_filter() on interfaces that are not IFF_RUNNING.
	the hardware should be reset and multicast filters set if/when the 
	interface is brought up.

	note that other network interface drivers besides if_wm.c should
	be inspected for this problem.

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