Subject: kern/23306: Kernel Segmentation Fault on wireless cards
To: None <gnats-bugs@gnats.netbsd.org>
From: pancake <pancake@phreaker.net>
List: netbsd-bugs
Date: 10/29/2003 17:57:32
>Number:         23306
>Category:       kern
>Synopsis:       Kernel Segmentation Fault on wireless cards
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Oct 29 18:00:00 UTC 2003
>Closed-Date:
>Last-Modified:
>Originator:     
>Release:        NetBSD 1.6ZD
>Organization:
	
>Environment:
	
	
System: NetBSD pl2 1.6ZD NetBSD 1.6ZD (PANCAKE_LAPTOP) #1: Sun Oct 26 02:32:21 UTC 2003 root@pl2:/usr/src/sys/arch/i386/compile/PANCAKE_LAPTOP i386
Architecture: i386
Machine: i386
>Description:
	NetBSD-current segfaults trying to put the wireless card in some
	invalid specific channel mode.
	That's because dev/ic/wi.c doesn't check return values of functions
	before using it as array pointer. This causes a kernel segfault.

>How-To-Repeat:
	To repeat this segfault:
	# ifconfig wi0 media DS11 mediaopt ibss

	It's NOT exploitable, just segfaultable. 
	
	I have a "Lucent wireless card" but I know that this segfaults also
	on prism-based, because the last kernel changes on wireless.

	a dmesg of my wi0 is:
	
wi0 at pcmcia0 function 0: Cabletron, RoamAbout 802.11 DS, Version 01.01
wi0: port 0x400-0x43fuhidev0 at uhub0 port 1 configuration 1 interface 0
wi0: using Lucent Technologies, WaveLAN/IEEE
wi0: Lucent Firmware: Station (6.4.1)
wi0: 11b rates: 1Mbps 2Mbps 5.5Mbps 11Mbps

>Fix:
	Just apply this patch to the official NetBSD kernel tree src.

--- dev/ic/wi.c.orig	2003-10-29 17:02:40.000000000 +0000
+++ dev/ic/wi.c	2003-10-29 17:14:11.000000000 +0000
@@ -104,6 +104,7 @@
 
 #include <machine/bus.h>
 
+#include <dev/ic/icpreg.h>
 #include <dev/ic/wi_ieee.h>
 #include <dev/ic/wireg.h>
 #include <dev/ic/wivar.h>
@@ -1077,9 +1078,14 @@
 	if (IFM_SUBTYPE(ime->ifm_media) == IFM_AUTO) {
 		i = -1;
 	} else {
-		struct ieee80211_rateset *rs =
-		    &ic->ic_sup_rates[ieee80211_chan2mode(ic,
-		        ic->ic_bss->ni_chan)];
+		struct ieee80211_rateset *rs = 0;
+		enum ieee80211_phymode phymode =
+			ieee80211_chan2mode(ic,ic->ic_bss->ni_chan);
+
+		if (phymode == ICP_INVALID_CHANNEL) 
+			return EINVAL;
+
+		rs = &ic->ic_sup_rates[phymode];
 		rate = ieee80211_media2rate(ime->ifm_media);
 		if (rate == 0)
 			return EINVAL;
>Release-Note:
>Audit-Trail:
>Unformatted: