Skip to content

Commit ac075bd

Browse files
committed
Merge tag 'mac80211-for-net-2021-04-08.2' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211
Johannes berg says: ==================== Various small fixes: * S1G beacon validation * potential leak in nl80211 * fast-RX confusion with 4-addr mode * erroneous WARN_ON that userspace can trigger * wrong time units in virt_wifi * rfkill userspace API breakage * TXQ AC confusing that led to traffic stopped forever * connection monitoring time after/before confusion * netlink beacon head validation buffer overrun ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 3583a4e + 9a6847b commit ac075bd

File tree

9 files changed

+99
-30
lines changed

9 files changed

+99
-30
lines changed

drivers/net/wireless/virt_wifi.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <net/cfg80211.h>
1313
#include <net/rtnetlink.h>
1414
#include <linux/etherdevice.h>
15+
#include <linux/math64.h>
1516
#include <linux/module.h>
1617

1718
static struct wiphy *common_wiphy;
@@ -168,11 +169,11 @@ static void virt_wifi_scan_result(struct work_struct *work)
168169
scan_result.work);
169170
struct wiphy *wiphy = priv_to_wiphy(priv);
170171
struct cfg80211_scan_info scan_info = { .aborted = false };
172+
u64 tsf = div_u64(ktime_get_boottime_ns(), 1000);
171173

172174
informed_bss = cfg80211_inform_bss(wiphy, &channel_5ghz,
173175
CFG80211_BSS_FTYPE_PRESP,
174-
fake_router_bssid,
175-
ktime_get_boottime_ns(),
176+
fake_router_bssid, tsf,
176177
WLAN_CAPABILITY_ESS, 0,
177178
(void *)&ssid, sizeof(ssid),
178179
DBM_TO_MBM(-50), GFP_KERNEL);

include/uapi/linux/rfkill.h

Lines changed: 68 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -86,34 +86,90 @@ enum rfkill_hard_block_reasons {
8686
* @op: operation code
8787
* @hard: hard state (0/1)
8888
* @soft: soft state (0/1)
89+
*
90+
* Structure used for userspace communication on /dev/rfkill,
91+
* used for events from the kernel and control to the kernel.
92+
*/
93+
struct rfkill_event {
94+
__u32 idx;
95+
__u8 type;
96+
__u8 op;
97+
__u8 soft;
98+
__u8 hard;
99+
} __attribute__((packed));
100+
101+
/**
102+
* struct rfkill_event_ext - events for userspace on /dev/rfkill
103+
* @idx: index of dev rfkill
104+
* @type: type of the rfkill struct
105+
* @op: operation code
106+
* @hard: hard state (0/1)
107+
* @soft: soft state (0/1)
89108
* @hard_block_reasons: valid if hard is set. One or several reasons from
90109
* &enum rfkill_hard_block_reasons.
91110
*
92111
* Structure used for userspace communication on /dev/rfkill,
93112
* used for events from the kernel and control to the kernel.
113+
*
114+
* See the extensibility docs below.
94115
*/
95-
struct rfkill_event {
116+
struct rfkill_event_ext {
96117
__u32 idx;
97118
__u8 type;
98119
__u8 op;
99120
__u8 soft;
100121
__u8 hard;
122+
123+
/*
124+
* older kernels will accept/send only up to this point,
125+
* and if extended further up to any chunk marked below
126+
*/
127+
101128
__u8 hard_block_reasons;
102129
} __attribute__((packed));
103130

104-
/*
105-
* We are planning to be backward and forward compatible with changes
106-
* to the event struct, by adding new, optional, members at the end.
107-
* When reading an event (whether the kernel from userspace or vice
108-
* versa) we need to accept anything that's at least as large as the
109-
* version 1 event size, but might be able to accept other sizes in
110-
* the future.
131+
/**
132+
* DOC: Extensibility
133+
*
134+
* Originally, we had planned to allow backward and forward compatible
135+
* changes by just adding fields at the end of the structure that are
136+
* then not reported on older kernels on read(), and not written to by
137+
* older kernels on write(), with the kernel reporting the size it did
138+
* accept as the result.
139+
*
140+
* This would have allowed userspace to detect on read() and write()
141+
* which kernel structure version it was dealing with, and if was just
142+
* recompiled it would have gotten the new fields, but obviously not
143+
* accessed them, but things should've continued to work.
144+
*
145+
* Unfortunately, while actually exercising this mechanism to add the
146+
* hard block reasons field, we found that userspace (notably systemd)
147+
* did all kinds of fun things not in line with this scheme:
148+
*
149+
* 1. treat the (expected) short writes as an error;
150+
* 2. ask to read sizeof(struct rfkill_event) but then compare the
151+
* actual return value to RFKILL_EVENT_SIZE_V1 and treat any
152+
* mismatch as an error.
153+
*
154+
* As a consequence, just recompiling with a new struct version caused
155+
* things to no longer work correctly on old and new kernels.
156+
*
157+
* Hence, we've rolled back &struct rfkill_event to the original version
158+
* and added &struct rfkill_event_ext. This effectively reverts to the
159+
* old behaviour for all userspace, unless it explicitly opts in to the
160+
* rules outlined here by using the new &struct rfkill_event_ext.
161+
*
162+
* Userspace using &struct rfkill_event_ext must adhere to the following
163+
* rules
111164
*
112-
* One exception is the kernel -- we already have two event sizes in
113-
* that we've made the 'hard' member optional since our only option
114-
* is to ignore it anyway.
165+
* 1. accept short writes, optionally using them to detect that it's
166+
* running on an older kernel;
167+
* 2. accept short reads, knowing that this means it's running on an
168+
* older kernel;
169+
* 3. treat reads that are as long as requested as acceptable, not
170+
* checking against RFKILL_EVENT_SIZE_V1 or such.
115171
*/
116-
#define RFKILL_EVENT_SIZE_V1 8
172+
#define RFKILL_EVENT_SIZE_V1 sizeof(struct rfkill_event)
117173

118174
/* ioctl for turning off rfkill-input (if present) */
119175
#define RFKILL_IOC_MAGIC 'R'

net/mac80211/cfg.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1788,8 +1788,10 @@ static int ieee80211_change_station(struct wiphy *wiphy,
17881788
}
17891789

17901790
if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
1791-
sta->sdata->u.vlan.sta)
1791+
sta->sdata->u.vlan.sta) {
1792+
ieee80211_clear_fast_rx(sta);
17921793
RCU_INIT_POINTER(sta->sdata->u.vlan.sta, NULL);
1794+
}
17931795

17941796
if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
17951797
ieee80211_vif_dec_num_mcast(sta->sdata);

net/mac80211/mlme.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4707,7 +4707,10 @@ static void ieee80211_sta_conn_mon_timer(struct timer_list *t)
47074707
timeout = sta->rx_stats.last_rx;
47084708
timeout += IEEE80211_CONNECTION_IDLE_TIME;
47094709

4710-
if (time_is_before_jiffies(timeout)) {
4710+
/* If timeout is after now, then update timer to fire at
4711+
* the later date, but do not actually probe at this time.
4712+
*/
4713+
if (time_is_after_jiffies(timeout)) {
47114714
mod_timer(&ifmgd->conn_mon_timer, round_jiffies_up(timeout));
47124715
return;
47134716
}

net/mac80211/tx.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3573,7 +3573,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
35733573
test_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags))
35743574
goto out;
35753575

3576-
if (vif->txqs_stopped[ieee80211_ac_from_tid(txq->tid)]) {
3576+
if (vif->txqs_stopped[txq->ac]) {
35773577
set_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags);
35783578
goto out;
35793579
}

net/rfkill/core.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ struct rfkill {
6969

7070
struct rfkill_int_event {
7171
struct list_head list;
72-
struct rfkill_event ev;
72+
struct rfkill_event_ext ev;
7373
};
7474

7575
struct rfkill_data {
@@ -253,7 +253,8 @@ static void rfkill_global_led_trigger_unregister(void)
253253
}
254254
#endif /* CONFIG_RFKILL_LEDS */
255255

256-
static void rfkill_fill_event(struct rfkill_event *ev, struct rfkill *rfkill,
256+
static void rfkill_fill_event(struct rfkill_event_ext *ev,
257+
struct rfkill *rfkill,
257258
enum rfkill_operation op)
258259
{
259260
unsigned long flags;
@@ -1237,7 +1238,7 @@ static ssize_t rfkill_fop_write(struct file *file, const char __user *buf,
12371238
size_t count, loff_t *pos)
12381239
{
12391240
struct rfkill *rfkill;
1240-
struct rfkill_event ev;
1241+
struct rfkill_event_ext ev;
12411242
int ret;
12421243

12431244
/* we don't need the 'hard' variable but accept it */

net/wireless/nl80211.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Copyright 2006-2010 Johannes Berg <[email protected]>
66
* Copyright 2013-2014 Intel Mobile Communications GmbH
77
* Copyright 2015-2017 Intel Deutschland GmbH
8-
* Copyright (C) 2018-2020 Intel Corporation
8+
* Copyright (C) 2018-2021 Intel Corporation
99
*/
1010

1111
#include <linux/if.h>
@@ -229,9 +229,13 @@ static int validate_beacon_head(const struct nlattr *attr,
229229
unsigned int len = nla_len(attr);
230230
const struct element *elem;
231231
const struct ieee80211_mgmt *mgmt = (void *)data;
232-
bool s1g_bcn = ieee80211_is_s1g_beacon(mgmt->frame_control);
233232
unsigned int fixedlen, hdrlen;
233+
bool s1g_bcn;
234234

235+
if (len < offsetofend(typeof(*mgmt), frame_control))
236+
goto err;
237+
238+
s1g_bcn = ieee80211_is_s1g_beacon(mgmt->frame_control);
235239
if (s1g_bcn) {
236240
fixedlen = offsetof(struct ieee80211_ext,
237241
u.s1g_beacon.variable);
@@ -5485,7 +5489,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
54855489
rdev, info->attrs[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP],
54865490
&params);
54875491
if (err)
5488-
return err;
5492+
goto out;
54895493
}
54905494

54915495
nl80211_calculate_ap_params(&params);

net/wireless/scan.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2352,14 +2352,16 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
23522352
return NULL;
23532353

23542354
if (ext) {
2355-
struct ieee80211_s1g_bcn_compat_ie *compat;
2356-
u8 *ie;
2355+
const struct ieee80211_s1g_bcn_compat_ie *compat;
2356+
const struct element *elem;
23572357

2358-
ie = (void *)cfg80211_find_ie(WLAN_EID_S1G_BCN_COMPAT,
2359-
variable, ielen);
2360-
if (!ie)
2358+
elem = cfg80211_find_elem(WLAN_EID_S1G_BCN_COMPAT,
2359+
variable, ielen);
2360+
if (!elem)
2361+
return NULL;
2362+
if (elem->datalen < sizeof(*compat))
23612363
return NULL;
2362-
compat = (void *)(ie + 2);
2364+
compat = (void *)elem->data;
23632365
bssid = ext->u.s1g_beacon.sa;
23642366
capability = le16_to_cpu(compat->compat_info);
23652367
beacon_int = le16_to_cpu(compat->beacon_int);

net/wireless/sme.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
529529
cfg80211_sme_free(wdev);
530530
}
531531

532-
if (WARN_ON(wdev->conn))
532+
if (wdev->conn)
533533
return -EINPROGRESS;
534534

535535
wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);

0 commit comments

Comments
 (0)