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 -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEH1e1rEeCd0AIMq6MB8qZga/fl8QFAmDAz24ACgkQB8qZga/f l8S1LQ/8CVe2fweF6mps0gktCgAAiLhCCpcqCiGqPFe6cmDfSJp7bvCj9YNL7LaG YvCwXlBAN7xpBwnGAXSvBpYC2Ru7KNfzTSqFfThbzPh4DLKxUfKsOK6Yel3yx6B3 gWDjT4zKpZ93k7DO1wdgO/MOvaOVbTe0F+wcLCvcZ3dpqHZuFqAK5FWlHUtlM2c3 Uc08O2WN2DrQR/Qnw0ErXK6pd8N87bnrTNd7vYf69Cmcp53GC4rQGRATQxEtm8LC DdlAQ4ensIfrexlFG+oCSISufwlKYBNW9PY0L10qNUzB6DJyRDVz1UybWEPcTZEy sS8nK4O98bGALWMi98Dqf/s/mQMrjs6THJIyJUQi+p2pHimDH43qwfcIAqoMcw0g 37aG67dEZDXkSYx+CPloBFPgELfDP726BFcVkRyUzdHEIZyGvIIEnEfr6LsIKXNS pDRrDyJOaNoHjGq0VzYvZ+7ETo8rqJHDWkNjEQX13jfa2r3kDTUAvauXkNTmez5N xTNN5XttlfNXvUgb+QWp35ZgfvwimLzVKGfPGBNl8vKaFc5tOGVnzaHU3WahOa1d ttzGRuiNuvb0OWZqIlxG8U8FPtXXpSy/+oKdP4ZbFOLeZXRqpJ85dMSpUAIOwYT5 E0bdOpgbx5C5LFhK4GXUT/Mx6nLBr3c3Jj5flhrGx2wg9+z+PVU= =evzy -----END PGP SIGNATURE----- Merge tag 'mac80211-for-net-2021-06-09' of git://git.kernel.org/pub/scm/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>
This commit is contained in:
commit
93124d4a90
|
@ -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__);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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>
|
||||
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -2014,27 +2014,10 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
|||
ieee80211_tx(sdata, sta, skb, false);
|
||||
}
|
||||
|
||||
bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
static bool ieee80211_validate_radiotap_len(struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_radiotap_iterator iterator;
|
||||
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;
|
||||
u16 rate = 0;
|
||||
bool rate_found = false;
|
||||
u8 rate_retries = 0;
|
||||
u16 rate_flags = 0;
|
||||
u8 mcs_known, mcs_flags, mcs_bw;
|
||||
u16 vht_known;
|
||||
u8 vht_mcs = 0, vht_nss = 0;
|
||||
int i;
|
||||
(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)))
|
||||
|
@ -2048,6 +2031,32 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
|
|||
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)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_radiotap_iterator iterator;
|
||||
struct ieee80211_radiotap_header *rthdr =
|
||||
(struct ieee80211_radiotap_header *) skb->data;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
|
||||
NULL);
|
||||
u16 txflags;
|
||||
u16 rate = 0;
|
||||
bool rate_found = false;
|
||||
u8 rate_retries = 0;
|
||||
u16 rate_flags = 0;
|
||||
u8 mcs_known, mcs_flags, mcs_bw;
|
||||
u16 vht_known;
|
||||
u8 vht_mcs = 0, vht_nss = 0;
|
||||
int i;
|
||||
|
||||
if (!ieee80211_validate_radiotap_len(skb))
|
||||
return false;
|
||||
|
||||
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
|
||||
IEEE80211_TX_CTL_DONTFRAG;
|
||||
|
||||
|
@ -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++) {
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue