Commit ac075bdd authored by David S. Miller's avatar David S. Miller

Merge tag 'mac80211-for-net-2021-04-08.2' of...

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 3583a4e8 9a6847ba
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include <net/rtnetlink.h> #include <net/rtnetlink.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/math64.h>
#include <linux/module.h> #include <linux/module.h>
static struct wiphy *common_wiphy; static struct wiphy *common_wiphy;
...@@ -168,11 +169,11 @@ static void virt_wifi_scan_result(struct work_struct *work) ...@@ -168,11 +169,11 @@ static void virt_wifi_scan_result(struct work_struct *work)
scan_result.work); scan_result.work);
struct wiphy *wiphy = priv_to_wiphy(priv); struct wiphy *wiphy = priv_to_wiphy(priv);
struct cfg80211_scan_info scan_info = { .aborted = false }; struct cfg80211_scan_info scan_info = { .aborted = false };
u64 tsf = div_u64(ktime_get_boottime_ns(), 1000);
informed_bss = cfg80211_inform_bss(wiphy, &channel_5ghz, informed_bss = cfg80211_inform_bss(wiphy, &channel_5ghz,
CFG80211_BSS_FTYPE_PRESP, CFG80211_BSS_FTYPE_PRESP,
fake_router_bssid, fake_router_bssid, tsf,
ktime_get_boottime_ns(),
WLAN_CAPABILITY_ESS, 0, WLAN_CAPABILITY_ESS, 0,
(void *)&ssid, sizeof(ssid), (void *)&ssid, sizeof(ssid),
DBM_TO_MBM(-50), GFP_KERNEL); DBM_TO_MBM(-50), GFP_KERNEL);
......
...@@ -86,34 +86,90 @@ enum rfkill_hard_block_reasons { ...@@ -86,34 +86,90 @@ enum rfkill_hard_block_reasons {
* @op: operation code * @op: operation code
* @hard: hard state (0/1) * @hard: hard state (0/1)
* @soft: soft state (0/1) * @soft: soft state (0/1)
*
* Structure used for userspace communication on /dev/rfkill,
* used for events from the kernel and control to the kernel.
*/
struct rfkill_event {
__u32 idx;
__u8 type;
__u8 op;
__u8 soft;
__u8 hard;
} __attribute__((packed));
/**
* struct rfkill_event_ext - events for userspace on /dev/rfkill
* @idx: index of dev rfkill
* @type: type of the rfkill struct
* @op: operation code
* @hard: hard state (0/1)
* @soft: soft state (0/1)
* @hard_block_reasons: valid if hard is set. One or several reasons from * @hard_block_reasons: valid if hard is set. One or several reasons from
* &enum rfkill_hard_block_reasons. * &enum rfkill_hard_block_reasons.
* *
* Structure used for userspace communication on /dev/rfkill, * Structure used for userspace communication on /dev/rfkill,
* used for events from the kernel and control to the kernel. * used for events from the kernel and control to the kernel.
*
* See the extensibility docs below.
*/ */
struct rfkill_event { struct rfkill_event_ext {
__u32 idx; __u32 idx;
__u8 type; __u8 type;
__u8 op; __u8 op;
__u8 soft; __u8 soft;
__u8 hard; __u8 hard;
/*
* older kernels will accept/send only up to this point,
* and if extended further up to any chunk marked below
*/
__u8 hard_block_reasons; __u8 hard_block_reasons;
} __attribute__((packed)); } __attribute__((packed));
/* /**
* We are planning to be backward and forward compatible with changes * DOC: Extensibility
* to the event struct, by adding new, optional, members at the end. *
* When reading an event (whether the kernel from userspace or vice * Originally, we had planned to allow backward and forward compatible
* versa) we need to accept anything that's at least as large as the * changes by just adding fields at the end of the structure that are
* version 1 event size, but might be able to accept other sizes in * then not reported on older kernels on read(), and not written to by
* the future. * older kernels on write(), with the kernel reporting the size it did
* accept as the result.
*
* This would have allowed userspace to detect on read() and write()
* which kernel structure version it was dealing with, and if was just
* recompiled it would have gotten the new fields, but obviously not
* accessed them, but things should've continued to work.
*
* Unfortunately, while actually exercising this mechanism to add the
* hard block reasons field, we found that userspace (notably systemd)
* did all kinds of fun things not in line with this scheme:
*
* 1. treat the (expected) short writes as an error;
* 2. ask to read sizeof(struct rfkill_event) but then compare the
* actual return value to RFKILL_EVENT_SIZE_V1 and treat any
* mismatch as an error.
*
* As a consequence, just recompiling with a new struct version caused
* things to no longer work correctly on old and new kernels.
*
* Hence, we've rolled back &struct rfkill_event to the original version
* and added &struct rfkill_event_ext. This effectively reverts to the
* old behaviour for all userspace, unless it explicitly opts in to the
* rules outlined here by using the new &struct rfkill_event_ext.
*
* Userspace using &struct rfkill_event_ext must adhere to the following
* rules
* *
* One exception is the kernel -- we already have two event sizes in * 1. accept short writes, optionally using them to detect that it's
* that we've made the 'hard' member optional since our only option * running on an older kernel;
* is to ignore it anyway. * 2. accept short reads, knowing that this means it's running on an
* older kernel;
* 3. treat reads that are as long as requested as acceptable, not
* checking against RFKILL_EVENT_SIZE_V1 or such.
*/ */
#define RFKILL_EVENT_SIZE_V1 8 #define RFKILL_EVENT_SIZE_V1 sizeof(struct rfkill_event)
/* ioctl for turning off rfkill-input (if present) */ /* ioctl for turning off rfkill-input (if present) */
#define RFKILL_IOC_MAGIC 'R' #define RFKILL_IOC_MAGIC 'R'
......
...@@ -1788,8 +1788,10 @@ static int ieee80211_change_station(struct wiphy *wiphy, ...@@ -1788,8 +1788,10 @@ static int ieee80211_change_station(struct wiphy *wiphy,
} }
if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
sta->sdata->u.vlan.sta) sta->sdata->u.vlan.sta) {
ieee80211_clear_fast_rx(sta);
RCU_INIT_POINTER(sta->sdata->u.vlan.sta, NULL); RCU_INIT_POINTER(sta->sdata->u.vlan.sta, NULL);
}
if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
ieee80211_vif_dec_num_mcast(sta->sdata); ieee80211_vif_dec_num_mcast(sta->sdata);
......
...@@ -4707,7 +4707,10 @@ static void ieee80211_sta_conn_mon_timer(struct timer_list *t) ...@@ -4707,7 +4707,10 @@ static void ieee80211_sta_conn_mon_timer(struct timer_list *t)
timeout = sta->rx_stats.last_rx; timeout = sta->rx_stats.last_rx;
timeout += IEEE80211_CONNECTION_IDLE_TIME; timeout += IEEE80211_CONNECTION_IDLE_TIME;
if (time_is_before_jiffies(timeout)) { /* If timeout is after now, then update timer to fire at
* the later date, but do not actually probe at this time.
*/
if (time_is_after_jiffies(timeout)) {
mod_timer(&ifmgd->conn_mon_timer, round_jiffies_up(timeout)); mod_timer(&ifmgd->conn_mon_timer, round_jiffies_up(timeout));
return; return;
} }
......
...@@ -3573,7 +3573,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, ...@@ -3573,7 +3573,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
test_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags)) test_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags))
goto out; goto out;
if (vif->txqs_stopped[ieee80211_ac_from_tid(txq->tid)]) { if (vif->txqs_stopped[txq->ac]) {
set_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags); set_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags);
goto out; goto out;
} }
......
...@@ -69,7 +69,7 @@ struct rfkill { ...@@ -69,7 +69,7 @@ struct rfkill {
struct rfkill_int_event { struct rfkill_int_event {
struct list_head list; struct list_head list;
struct rfkill_event ev; struct rfkill_event_ext ev;
}; };
struct rfkill_data { struct rfkill_data {
...@@ -253,7 +253,8 @@ static void rfkill_global_led_trigger_unregister(void) ...@@ -253,7 +253,8 @@ static void rfkill_global_led_trigger_unregister(void)
} }
#endif /* CONFIG_RFKILL_LEDS */ #endif /* CONFIG_RFKILL_LEDS */
static void rfkill_fill_event(struct rfkill_event *ev, struct rfkill *rfkill, static void rfkill_fill_event(struct rfkill_event_ext *ev,
struct rfkill *rfkill,
enum rfkill_operation op) enum rfkill_operation op)
{ {
unsigned long flags; unsigned long flags;
...@@ -1237,7 +1238,7 @@ static ssize_t rfkill_fop_write(struct file *file, const char __user *buf, ...@@ -1237,7 +1238,7 @@ static ssize_t rfkill_fop_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos) size_t count, loff_t *pos)
{ {
struct rfkill *rfkill; struct rfkill *rfkill;
struct rfkill_event ev; struct rfkill_event_ext ev;
int ret; int ret;
/* we don't need the 'hard' variable but accept it */ /* we don't need the 'hard' variable but accept it */
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2015-2017 Intel Deutschland GmbH * Copyright 2015-2017 Intel Deutschland GmbH
* Copyright (C) 2018-2020 Intel Corporation * Copyright (C) 2018-2021 Intel Corporation
*/ */
#include <linux/if.h> #include <linux/if.h>
...@@ -229,9 +229,13 @@ static int validate_beacon_head(const struct nlattr *attr, ...@@ -229,9 +229,13 @@ static int validate_beacon_head(const struct nlattr *attr,
unsigned int len = nla_len(attr); unsigned int len = nla_len(attr);
const struct element *elem; const struct element *elem;
const struct ieee80211_mgmt *mgmt = (void *)data; const struct ieee80211_mgmt *mgmt = (void *)data;
bool s1g_bcn = ieee80211_is_s1g_beacon(mgmt->frame_control);
unsigned int fixedlen, hdrlen; unsigned int fixedlen, hdrlen;
bool s1g_bcn;
if (len < offsetofend(typeof(*mgmt), frame_control))
goto err;
s1g_bcn = ieee80211_is_s1g_beacon(mgmt->frame_control);
if (s1g_bcn) { if (s1g_bcn) {
fixedlen = offsetof(struct ieee80211_ext, fixedlen = offsetof(struct ieee80211_ext,
u.s1g_beacon.variable); u.s1g_beacon.variable);
...@@ -5485,7 +5489,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) ...@@ -5485,7 +5489,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
rdev, info->attrs[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP], rdev, info->attrs[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP],
&params); &params);
if (err) if (err)
return err; goto out;
} }
nl80211_calculate_ap_params(&params); nl80211_calculate_ap_params(&params);
......
...@@ -2352,14 +2352,16 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, ...@@ -2352,14 +2352,16 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
return NULL; return NULL;
if (ext) { if (ext) {
struct ieee80211_s1g_bcn_compat_ie *compat; const struct ieee80211_s1g_bcn_compat_ie *compat;
u8 *ie; const struct element *elem;
ie = (void *)cfg80211_find_ie(WLAN_EID_S1G_BCN_COMPAT, elem = cfg80211_find_elem(WLAN_EID_S1G_BCN_COMPAT,
variable, ielen); variable, ielen);
if (!ie) if (!elem)
return NULL;
if (elem->datalen < sizeof(*compat))
return NULL; return NULL;
compat = (void *)(ie + 2); compat = (void *)elem->data;
bssid = ext->u.s1g_beacon.sa; bssid = ext->u.s1g_beacon.sa;
capability = le16_to_cpu(compat->compat_info); capability = le16_to_cpu(compat->compat_info);
beacon_int = le16_to_cpu(compat->beacon_int); beacon_int = le16_to_cpu(compat->beacon_int);
......
...@@ -529,7 +529,7 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev, ...@@ -529,7 +529,7 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
cfg80211_sme_free(wdev); cfg80211_sme_free(wdev);
} }
if (WARN_ON(wdev->conn)) if (wdev->conn)
return -EINPROGRESS; return -EINPROGRESS;
wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL); wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment