diff mbox

[v2,2/2] mac80211: guard against invalid ptr deref

Message ID 1432285043-8878-2-git-send-email-michal.kazior@tieto.com (mailing list archive)
State Rejected
Delegated to: Johannes Berg
Headers show

Commit Message

Michal Kazior May 22, 2015, 8:57 a.m. UTC
It was possible for mac80211 to be coerced into an
unexpected flow causing sdata union to become
corrupted. Station pointer was put into
sdata->u.vlan.sta memory location while it was
really master AP's sdata->u.ap.next_beacon. This
led to station entry being later freed as
next_beacon before __sta_info_flush() in
ieee80211_stop_ap() and a subsequent invalid
pointer dereference crash.

The problem was that ieee80211_ptr->use_4addr
wasn't cleared on interface type changes.

This could be reproduced with the following steps:

 # host A and host B have just booted; no
 # wpa_s/hostapd running; all vifs are down
 host A> iw wlan0 set type station
 host A> iw wlan0 set 4addr on
 host A> printf 'interface=wlan0\nssid=4addrcrash\nchannel=1\nwds_sta=1' > /tmp/hconf
 host A> hostapd -B /tmp/conf
 host B> iw wlan0 set 4addr on
 host B> ifconfig wlan0 up
 host B> iw wlan0 connect -w hostAssid
 host A> pkill hostapd
 # host A crashed:

 [  127.928192] BUG: unable to handle kernel NULL pointer dereference at 00000000000006c8
 [  127.929014] IP: [<ffffffff816f4f32>] __sta_info_flush+0xac/0x158
 ...
 [  127.934578]  [<ffffffff8170789e>] ieee80211_stop_ap+0x139/0x26c
 [  127.934578]  [<ffffffff8100498f>] ? dump_trace+0x279/0x28a
 [  127.934578]  [<ffffffff816dc661>] __cfg80211_stop_ap+0x84/0x191
 [  127.934578]  [<ffffffff816dc7ad>] cfg80211_stop_ap+0x3f/0x58
 [  127.934578]  [<ffffffff816c5ad6>] nl80211_stop_ap+0x1b/0x1d
 [  127.934578]  [<ffffffff815e53f8>] genl_family_rcv_msg+0x259/0x2b5

Even though this can and should be fixed in
cfg80211 it still makes sense to add a sanity
check to mac80211 to prevent future problems.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---

Notes:
    v2:
     * improve commit log [Johannes]

 net/mac80211/cfg.c | 6 ++++++
 1 file changed, 6 insertions(+)

Comments

Johannes Berg May 29, 2015, 11:10 a.m. UTC | #1
On Fri, 2015-05-22 at 10:57 +0200, Michal Kazior wrote:
> It was possible for mac80211 to be coerced into an
> unexpected flow causing sdata union to become
> corrupted. Station pointer was put into
> sdata->u.vlan.sta memory location while it was
> really master AP's sdata->u.ap.next_beacon. This
> led to station entry being later freed as
> next_beacon before __sta_info_flush() in
> ieee80211_stop_ap() and a subsequent invalid
> pointer dereference crash.
> 
> The problem was that ieee80211_ptr->use_4addr
> wasn't cleared on interface type changes.
> 
> This could be reproduced with the following steps:
> 
>  # host A and host B have just booted; no
>  # wpa_s/hostapd running; all vifs are down
>  host A> iw wlan0 set type station
>  host A> iw wlan0 set 4addr on
>  host A> printf 'interface=wlan0\nssid=4addrcrash\nchannel=1\nwds_sta=1' > /tmp/hconf
>  host A> hostapd -B /tmp/conf
>  host B> iw wlan0 set 4addr on
>  host B> ifconfig wlan0 up
>  host B> iw wlan0 connect -w hostAssid
>  host A> pkill hostapd
>  # host A crashed:
> 
>  [  127.928192] BUG: unable to handle kernel NULL pointer dereference at 00000000000006c8
>  [  127.929014] IP: [<ffffffff816f4f32>] __sta_info_flush+0xac/0x158
>  ...
>  [  127.934578]  [<ffffffff8170789e>] ieee80211_stop_ap+0x139/0x26c
>  [  127.934578]  [<ffffffff8100498f>] ? dump_trace+0x279/0x28a
>  [  127.934578]  [<ffffffff816dc661>] __cfg80211_stop_ap+0x84/0x191
>  [  127.934578]  [<ffffffff816dc7ad>] cfg80211_stop_ap+0x3f/0x58
>  [  127.934578]  [<ffffffff816c5ad6>] nl80211_stop_ap+0x1b/0x1d
>  [  127.934578]  [<ffffffff815e53f8>] genl_family_rcv_msg+0x259/0x2b5
> 
> Even though this can and should be fixed in
> cfg80211 it still makes sense to add a sanity
> check to mac80211 to prevent future problems.

I'm a bit undecided about this. Is this really the only place that
assumes use_4addr implies that it's a VLAN, in a context like this?

johannes

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Michal Kazior May 29, 2015, 11:34 a.m. UTC | #2
On 29 May 2015 at 13:10, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Fri, 2015-05-22 at 10:57 +0200, Michal Kazior wrote:
>> It was possible for mac80211 to be coerced into an
>> unexpected flow causing sdata union to become
>> corrupted. Station pointer was put into
>> sdata->u.vlan.sta memory location while it was
>> really master AP's sdata->u.ap.next_beacon. This
>> led to station entry being later freed as
>> next_beacon before __sta_info_flush() in
>> ieee80211_stop_ap() and a subsequent invalid
>> pointer dereference crash.
>>
>> The problem was that ieee80211_ptr->use_4addr
>> wasn't cleared on interface type changes.
[...]
>> Even though this can and should be fixed in
>> cfg80211 it still makes sense to add a sanity
>> check to mac80211 to prevent future problems.
>
> I'm a bit undecided about this. Is this really the only place that
> assumes use_4addr implies that it's a VLAN, in a context like this?

Hmm.. I guess TDLS could also have use_4addr and still be a
IFTYPE_STATION, right? In which case parent condition should be
modified instead:

 if (vlansdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
     params->vlan->ieee80211_ptr->use_4addr) { ...


Micha?
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Johannes Berg May 29, 2015, 11:39 a.m. UTC | #3
On Fri, 2015-05-29 at 13:34 +0200, Michal Kazior wrote:

> > I'm a bit undecided about this. Is this really the only place that
> > assumes use_4addr implies that it's a VLAN, in a context like this?
> 
> Hmm.. I guess TDLS could also have use_4addr and still be a
> IFTYPE_STATION, right? 

No, TDLS can neither get here (VLAN assignment) nor does it actually set
use_4addr. The only other thing that can set use_4addr is the station
interface itself, but then we also can't get here.

That wasn't really my point though - I was thinking more along the lines
of code in rx.c, tx.c that just checks use_4addr? Not really sure.

johannes


--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Michal Kazior May 29, 2015, 11:48 a.m. UTC | #4
On 29 May 2015 at 13:39, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Fri, 2015-05-29 at 13:34 +0200, Michal Kazior wrote:
>
>> > I'm a bit undecided about this. Is this really the only place that
>> > assumes use_4addr implies that it's a VLAN, in a context like this?
>>
>> Hmm.. I guess TDLS could also have use_4addr and still be a
>> IFTYPE_STATION, right?
>
> No, TDLS can neither get here (VLAN assignment) nor does it actually set
> use_4addr. The only other thing that can set use_4addr is the station
> interface itself, but then we also can't get here.

Good point.


> That wasn't really my point though - I was thinking more along the lines
> of code in rx.c, tx.c that just checks use_4addr? Not really sure.

From what I see wdev.use_4addr is always used after checking for
IFTYPE_AP_VLAN. u.mgd.use_4addr on the other hand is used after
checking for IFTYPE_STATION.


Micha?
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index bb9f83640b46..d1f8d615701c 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1395,6 +1395,12 @@  static int ieee80211_change_station(struct wiphy *wiphy,
 		vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
 
 		if (params->vlan->ieee80211_ptr->use_4addr) {
+			if (vlansdata->vif.type != NL80211_IFTYPE_AP_VLAN) {
+				WARN_ON(1);
+				err = -EINVAL;
+				goto out_err;
+			}
+
 			if (vlansdata->u.vlan.sta) {
 				err = -EBUSY;
 				goto out_err;