Skip to content

Commit

Permalink
Merge tag 'mac80211-for-net-2021-06-09' of git://git.kernel.org/pub/s…
Browse files Browse the repository at this point in the history
…cm/linux/kernel/git/jberg/mac80211

Johannes berg says:

====================
A fair number of fixes:
 * fix more fallout from RTNL locking changes
 * fixes for some of the bugs found by syzbot
 * drop multicast fragments in mac80211 to align
   with the spec and what drivers are doing now
 * fix NULL-ptr deref in radiotap injection
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jun 9, 2021
2 parents a8b897c + a979954 commit 93124d4
Show file tree
Hide file tree
Showing 14 changed files with 109 additions and 52 deletions.
5 changes: 5 additions & 0 deletions drivers/net/wireless/mac80211_hwsim.c
Original file line number Diff line number Diff line change
Expand Up @@ -1693,8 +1693,13 @@ static int mac80211_hwsim_start(struct ieee80211_hw *hw)
static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
{
struct mac80211_hwsim_data *data = hw->priv;

data->started = false;
hrtimer_cancel(&data->beacon_timer);

while (!skb_queue_empty(&data->pending))
ieee80211_free_txskb(hw, skb_dequeue(&data->pending));

wiphy_dbg(hw->wiphy, "%s\n", __func__);
}

Expand Down
4 changes: 2 additions & 2 deletions drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -2284,7 +2284,7 @@ static int rtw_cfg80211_add_monitor_if(struct adapter *padapter, char *name, str
mon_wdev->iftype = NL80211_IFTYPE_MONITOR;
mon_ndev->ieee80211_ptr = mon_wdev;

ret = register_netdevice(mon_ndev);
ret = cfg80211_register_netdevice(mon_ndev);
if (ret) {
goto out;
}
Expand Down Expand Up @@ -2360,7 +2360,7 @@ static int cfg80211_rtw_del_virtual_intf(struct wiphy *wiphy,
adapter = rtw_netdev_priv(ndev);
pwdev_priv = adapter_wdev_data(adapter);

unregister_netdevice(ndev);
cfg80211_unregister_netdevice(ndev);

if (ndev == pwdev_priv->pmon_ndev) {
pwdev_priv->pmon_ndev = NULL;
Expand Down
9 changes: 7 additions & 2 deletions include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -5537,7 +5537,7 @@ void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw,
*
* This function iterates over the interfaces associated with a given
* hardware that are currently active and calls the callback for them.
* This version can only be used while holding the RTNL.
* This version can only be used while holding the wiphy mutex.
*
* @hw: the hardware struct of which the interfaces should be iterated over
* @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags
Expand Down Expand Up @@ -6392,7 +6392,12 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,

/**
* ieee80211_parse_tx_radiotap - Sanity-check and parse the radiotap header
* of injected frames
* of injected frames.
*
* To accurately parse and take into account rate and retransmission fields,
* you must initialize the chandef field in the ieee80211_tx_info structure
* of the skb before calling this function.
*
* @skb: packet injected by userspace
* @dev: the &struct device of this 802.11 device
*/
Expand Down
11 changes: 9 additions & 2 deletions net/mac80211/debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2018 - 2019 Intel Corporation
* Copyright (C) 2018 - 2019, 2021 Intel Corporation
*/

#include <linux/debugfs.h>
Expand Down Expand Up @@ -387,10 +387,17 @@ static ssize_t reset_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_local *local = file->private_data;
int ret;

rtnl_lock();
wiphy_lock(local->hw.wiphy);
__ieee80211_suspend(&local->hw, NULL);
__ieee80211_resume(&local->hw);
ret = __ieee80211_resume(&local->hw);
wiphy_unlock(local->hw.wiphy);

if (ret)
cfg80211_shutdown_all_interfaces(local->hw.wiphy);

rtnl_unlock();

return count;
Expand Down
2 changes: 1 addition & 1 deletion net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -1442,7 +1442,7 @@ ieee80211_get_sband(struct ieee80211_sub_if_data *sdata)
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);

if (WARN_ON_ONCE(!chanctx_conf)) {
if (!chanctx_conf) {
rcu_read_unlock();
return NULL;
}
Expand Down
19 changes: 12 additions & 7 deletions net/mac80211/iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -476,14 +476,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
GFP_KERNEL);
}

/* APs need special treatment */
if (sdata->vif.type == NL80211_IFTYPE_AP) {
struct ieee80211_sub_if_data *vlan, *tmpsdata;

/* down all dependent devices, that is VLANs */
list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
u.vlan.list)
dev_close(vlan->dev);
WARN_ON(!list_empty(&sdata->u.ap.vlans));
} else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
/* remove all packets in parent bc_buf pointing to this dev */
Expand Down Expand Up @@ -641,6 +634,15 @@ static int ieee80211_stop(struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);

/* close all dependent VLAN interfaces before locking wiphy */
if (sdata->vif.type == NL80211_IFTYPE_AP) {
struct ieee80211_sub_if_data *vlan, *tmpsdata;

list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
u.vlan.list)
dev_close(vlan->dev);
}

wiphy_lock(sdata->local->hw.wiphy);
ieee80211_do_stop(sdata, true);
wiphy_unlock(sdata->local->hw.wiphy);
Expand Down Expand Up @@ -1591,6 +1593,9 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,

switch (sdata->vif.type) {
case NL80211_IFTYPE_AP:
if (!list_empty(&sdata->u.ap.vlans))
return -EBUSY;
break;
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_OCB:
Expand Down
7 changes: 6 additions & 1 deletion net/mac80211/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ static void ieee80211_restart_work(struct work_struct *work)
struct ieee80211_local *local =
container_of(work, struct ieee80211_local, restart_work);
struct ieee80211_sub_if_data *sdata;
int ret;

/* wait for scan work complete */
flush_workqueue(local->workqueue);
Expand Down Expand Up @@ -301,8 +302,12 @@ static void ieee80211_restart_work(struct work_struct *work)
/* wait for all packet processing to be done */
synchronize_net();

ieee80211_reconfig(local);
ret = ieee80211_reconfig(local);
wiphy_unlock(local->hw.wiphy);

if (ret)
cfg80211_shutdown_all_interfaces(local->hw.wiphy);

rtnl_unlock();
}

Expand Down
9 changes: 3 additions & 6 deletions net/mac80211/rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -2240,17 +2240,15 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
sc = le16_to_cpu(hdr->seq_ctrl);
frag = sc & IEEE80211_SCTL_FRAG;

if (is_multicast_ether_addr(hdr->addr1)) {
I802_DEBUG_INC(rx->local->dot11MulticastReceivedFrameCount);
goto out_no_led;
}

if (rx->sta)
cache = &rx->sta->frags;

if (likely(!ieee80211_has_morefrags(fc) && frag == 0))
goto out;

if (is_multicast_ether_addr(hdr->addr1))
return RX_DROP_MONITOR;

I802_DEBUG_INC(rx->local->rx_handlers_fragments);

if (skb_linearize(rx->skb))
Expand Down Expand Up @@ -2376,7 +2374,6 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)

out:
ieee80211_led_rx(rx->local);
out_no_led:
if (rx->sta)
rx->sta->rx_stats.packets++;
return RX_CONTINUE;
Expand Down
21 changes: 16 additions & 5 deletions net/mac80211/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,13 +251,24 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
struct ieee80211_mgmt *mgmt = (void *)skb->data;
struct ieee80211_bss *bss;
struct ieee80211_channel *channel;
size_t min_hdr_len = offsetof(struct ieee80211_mgmt,
u.probe_resp.variable);

if (!ieee80211_is_probe_resp(mgmt->frame_control) &&
!ieee80211_is_beacon(mgmt->frame_control) &&
!ieee80211_is_s1g_beacon(mgmt->frame_control))
return;

if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
if (skb->len < 15)
return;
} else if (skb->len < 24 ||
(!ieee80211_is_probe_resp(mgmt->frame_control) &&
!ieee80211_is_beacon(mgmt->frame_control)))
if (ieee80211_is_s1g_short_beacon(mgmt->frame_control))
min_hdr_len = offsetof(struct ieee80211_ext,
u.s1g_short_beacon.variable);
else
min_hdr_len = offsetof(struct ieee80211_ext,
u.s1g_beacon);
}

if (skb->len < min_hdr_len)
return;

sdata1 = rcu_dereference(local->scan_sdata);
Expand Down
52 changes: 36 additions & 16 deletions net/mac80211/tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -2014,6 +2014,26 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
ieee80211_tx(sdata, sta, skb, false);
}

static bool ieee80211_validate_radiotap_len(struct sk_buff *skb)
{
struct ieee80211_radiotap_header *rthdr =
(struct ieee80211_radiotap_header *)skb->data;

/* check for not even having the fixed radiotap header part */
if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
return false; /* too short to be possibly valid */

/* is it a header version we can trust to find length from? */
if (unlikely(rthdr->it_version))
return false; /* only version 0 is supported */

/* does the skb contain enough to deliver on the alleged length? */
if (unlikely(skb->len < ieee80211_get_radiotap_len(skb->data)))
return false; /* skb too short for claimed rt header extent */

return true;
}

bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
struct net_device *dev)
{
Expand All @@ -2022,8 +2042,6 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
struct ieee80211_radiotap_header *rthdr =
(struct ieee80211_radiotap_header *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_supported_band *sband =
local->hw.wiphy->bands[info->band];
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
NULL);
u16 txflags;
Expand All @@ -2036,17 +2054,8 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
u8 vht_mcs = 0, vht_nss = 0;
int i;

/* check for not even having the fixed radiotap header part */
if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
return false; /* too short to be possibly valid */

/* is it a header version we can trust to find length from? */
if (unlikely(rthdr->it_version))
return false; /* only version 0 is supported */

/* does the skb contain enough to deliver on the alleged length? */
if (unlikely(skb->len < ieee80211_get_radiotap_len(skb->data)))
return false; /* skb too short for claimed rt header extent */
if (!ieee80211_validate_radiotap_len(skb))
return false;

info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
IEEE80211_TX_CTL_DONTFRAG;
Expand Down Expand Up @@ -2186,6 +2195,9 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
return false;

if (rate_found) {
struct ieee80211_supported_band *sband =
local->hw.wiphy->bands[info->band];

info->control.flags |= IEEE80211_TX_CTRL_RATE_INJECT;

for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
Expand All @@ -2199,7 +2211,7 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
} else if (rate_flags & IEEE80211_TX_RC_VHT_MCS) {
ieee80211_rate_set_vht(info->control.rates, vht_mcs,
vht_nss);
} else {
} else if (sband) {
for (i = 0; i < sband->n_bitrates; i++) {
if (rate * 5 != sband->bitrates[i].bitrate)
continue;
Expand Down Expand Up @@ -2236,8 +2248,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
IEEE80211_TX_CTL_INJECTED;

/* Sanity-check and process the injection radiotap header */
if (!ieee80211_parse_tx_radiotap(skb, dev))
/* Sanity-check the length of the radiotap header */
if (!ieee80211_validate_radiotap_len(skb))
goto fail;

/* we now know there is a radiotap header with a length we can use */
Expand Down Expand Up @@ -2351,6 +2363,14 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
ieee80211_select_queue_80211(sdata, skb, hdr);
skb_set_queue_mapping(skb, ieee80211_ac_from_tid(skb->priority));

/*
* Process the radiotap header. This will now take into account the
* selected chandef above to accurately set injection rates and
* retransmissions.
*/
if (!ieee80211_parse_tx_radiotap(skb, dev))
goto fail_rcu;

/* remove the injection radiotap header */
skb_pull(skb, len_rthdr);

Expand Down
2 changes: 0 additions & 2 deletions net/mac80211/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -2178,8 +2178,6 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local)
list_for_each_entry(ctx, &local->chanctx_list, list)
ctx->driver_present = false;
mutex_unlock(&local->chanctx_mtx);

cfg80211_shutdown_all_interfaces(local->hw.wiphy);
}

static void ieee80211_assign_chanctx(struct ieee80211_local *local,
Expand Down
13 changes: 5 additions & 8 deletions net/wireless/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1340,6 +1340,11 @@ void cfg80211_register_wdev(struct cfg80211_registered_device *rdev,
rdev->devlist_generation++;
wdev->registered = true;

if (wdev->netdev &&
sysfs_create_link(&wdev->netdev->dev.kobj, &rdev->wiphy.dev.kobj,
"phy80211"))
pr_err("failed to add phy80211 symlink to netdev!\n");

nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
}

Expand All @@ -1365,14 +1370,6 @@ int cfg80211_register_netdevice(struct net_device *dev)
if (ret)
goto out;

if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj,
"phy80211")) {
pr_err("failed to add phy80211 symlink to netdev!\n");
unregister_netdevice(dev);
ret = -EINVAL;
goto out;
}

cfg80211_register_wdev(rdev, wdev);
ret = 0;
out:
Expand Down
4 changes: 4 additions & 0 deletions net/wireless/sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ static int wiphy_resume(struct device *dev)
if (rdev->wiphy.registered && rdev->ops->resume)
ret = rdev_resume(rdev);
wiphy_unlock(&rdev->wiphy);

if (ret)
cfg80211_shutdown_all_interfaces(&rdev->wiphy);

rtnl_unlock();

return ret;
Expand Down
3 changes: 3 additions & 0 deletions net/wireless/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1059,6 +1059,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
case NL80211_IFTYPE_MESH_POINT:
/* mesh should be handled? */
break;
case NL80211_IFTYPE_OCB:
cfg80211_leave_ocb(rdev, dev);
break;
default:
break;
}
Expand Down

0 comments on commit 93124d4

Please sign in to comment.