aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@nbd.name>2023-03-29 17:54:19 +0200
committerFelix Fietkau <nbd@nbd.name>2023-03-30 11:40:11 +0200
commitd54c91bd9ab3c54ee06923eafbd67047816a37e4 (patch)
tree877e49513e160fbae19c6a7a3e0647387bec4683 /package/kernel/mac80211
parent9186da4027bc8d23912621b5471e98e9526f2878 (diff)
downloadupstream-d54c91bd9ab3c54ee06923eafbd67047816a37e4.tar.gz
upstream-d54c91bd9ab3c54ee06923eafbd67047816a37e4.tar.bz2
upstream-d54c91bd9ab3c54ee06923eafbd67047816a37e4.zip
mac80211, mt76: add fixes for recently discovered security issues
Fixes CVE-2022-47522 Signed-off-by: Felix Fietkau <nbd@nbd.name>
Diffstat (limited to 'package/kernel/mac80211')
-rw-r--r--package/kernel/mac80211/patches/subsys/330-wifi-ieee80211-correctly-mark-FTM-frames-non-buffera.patch134
-rw-r--r--package/kernel/mac80211/patches/subsys/331-wifi-mac80211-flush-queues-on-STA-removal.patch36
-rw-r--r--package/kernel/mac80211/patches/subsys/332-wifi-iwlwifi-mvm-support-flush-on-AP-interfaces.patch34
-rw-r--r--package/kernel/mac80211/patches/subsys/333-wifi-mac80211-add-flush_sta-method.patch91
-rw-r--r--package/kernel/mac80211/patches/subsys/334-wifi-iwlwifi-mvm-support-new-flush_sta-method.patch53
5 files changed, 348 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/subsys/330-wifi-ieee80211-correctly-mark-FTM-frames-non-buffera.patch b/package/kernel/mac80211/patches/subsys/330-wifi-ieee80211-correctly-mark-FTM-frames-non-buffera.patch
new file mode 100644
index 0000000000..9c98d9e6d9
--- /dev/null
+++ b/package/kernel/mac80211/patches/subsys/330-wifi-ieee80211-correctly-mark-FTM-frames-non-buffera.patch
@@ -0,0 +1,134 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Wed, 29 Mar 2023 16:46:26 +0200
+Subject: [PATCH] wifi: ieee80211: correctly mark FTM frames non-bufferable
+
+The checks of whether or not a frame is bufferable were not
+taking into account that some action frames aren't, such as
+FTM. Check this, which requires some changes to the function
+ieee80211_is_bufferable_mmpdu() since we need the whole skb
+for the checks now.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Reviewed-by: Greenman, Gregory <gregory.greenman@intel.com>
+Reviewed-by: Peer, Ilan <ilan.peer@intel.com>
+---
+
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+@@ -601,8 +601,9 @@ static void iwl_mvm_skb_prepare_status(s
+
+ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,
+ struct ieee80211_tx_info *info,
+- struct ieee80211_hdr *hdr)
++ struct sk_buff *skb)
+ {
++ struct ieee80211_hdr *hdr = (void *)skb->data;
+ struct iwl_mvm_vif *mvmvif =
+ iwl_mvm_vif_from_mac80211(info->control.vif);
+ __le16 fc = hdr->frame_control;
+@@ -621,7 +622,7 @@ static int iwl_mvm_get_ctrl_vif_queue(st
+ * reason 7 ("Class 3 frame received from nonassociated STA").
+ */
+ if (ieee80211_is_mgmt(fc) &&
+- (!ieee80211_is_bufferable_mmpdu(fc) ||
++ (!ieee80211_is_bufferable_mmpdu(skb) ||
+ ieee80211_is_deauth(fc) || ieee80211_is_disassoc(fc)))
+ return mvm->probe_queue;
+
+@@ -740,7 +741,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mv
+ else
+ sta_id = mvmvif->mcast_sta.sta_id;
+
+- queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info, hdr);
++ queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info, skb);
+ } else if (info.control.vif->type == NL80211_IFTYPE_MONITOR) {
+ queue = mvm->snif_queue;
+ sta_id = mvm->snif_sta.sta_id;
+--- a/include/linux/ieee80211.h
++++ b/include/linux/ieee80211.h
+@@ -772,20 +772,6 @@ static inline bool ieee80211_is_any_null
+ }
+
+ /**
+- * ieee80211_is_bufferable_mmpdu - check if frame is bufferable MMPDU
+- * @fc: frame control field in little-endian byteorder
+- */
+-static inline bool ieee80211_is_bufferable_mmpdu(__le16 fc)
+-{
+- /* IEEE 802.11-2012, definition of "bufferable management frame";
+- * note that this ignores the IBSS special case. */
+- return ieee80211_is_mgmt(fc) &&
+- (ieee80211_is_action(fc) ||
+- ieee80211_is_disassoc(fc) ||
+- ieee80211_is_deauth(fc));
+-}
+-
+-/**
+ * ieee80211_is_first_frag - check if IEEE80211_SCTL_FRAG is not set
+ * @seq_ctrl: frame sequence control bytes in little-endian byteorder
+ */
+@@ -4121,6 +4107,44 @@ static inline u8 *ieee80211_get_DA(struc
+ }
+
+ /**
++ * ieee80211_is_bufferable_mmpdu - check if frame is bufferable MMPDU
++ * @skb: the skb to check, starting with the 802.11 header
++ */
++static inline bool ieee80211_is_bufferable_mmpdu(struct sk_buff *skb)
++{
++ struct ieee80211_mgmt *mgmt = (void *)skb->data;
++ __le16 fc = mgmt->frame_control;
++
++ /*
++ * IEEE 802.11 REVme D2.0 definition of bufferable MMPDU;
++ * note that this ignores the IBSS special case.
++ */
++ if (!ieee80211_is_mgmt(fc))
++ return false;
++
++ if (ieee80211_is_disassoc(fc) || ieee80211_is_deauth(fc))
++ return true;
++
++ if (!ieee80211_is_action(fc))
++ return false;
++
++ if (skb->len < offsetofend(typeof(*mgmt), u.action.u.ftm.action_code))
++ return true;
++
++ /* action frame - additionally check for non-bufferable FTM */
++
++ if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC &&
++ mgmt->u.action.category != WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION)
++ return true;
++
++ if (mgmt->u.action.u.ftm.action_code == WLAN_PUB_ACTION_FTM_REQUEST ||
++ mgmt->u.action.u.ftm.action_code == WLAN_PUBLIC_ACTION_FTM_RESPONSE)
++ return false;
++
++ return true;
++}
++
++/**
+ * _ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame
+ * @hdr: the frame (buffer must include at least the first octet of payload)
+ */
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -488,7 +488,7 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
+ int ac = skb_get_queue_mapping(tx->skb);
+
+ if (ieee80211_is_mgmt(hdr->frame_control) &&
+- !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) {
++ !ieee80211_is_bufferable_mmpdu(tx->skb)) {
+ info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
+ return TX_CONTINUE;
+ }
+@@ -1325,7 +1325,7 @@ static struct txq_info *ieee80211_get_tx
+ if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
+ unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
+ if ((!ieee80211_is_mgmt(hdr->frame_control) ||
+- ieee80211_is_bufferable_mmpdu(hdr->frame_control) ||
++ ieee80211_is_bufferable_mmpdu(skb) ||
+ vif->type == NL80211_IFTYPE_STATION) &&
+ sta && sta->uploaded) {
+ /*
diff --git a/package/kernel/mac80211/patches/subsys/331-wifi-mac80211-flush-queues-on-STA-removal.patch b/package/kernel/mac80211/patches/subsys/331-wifi-mac80211-flush-queues-on-STA-removal.patch
new file mode 100644
index 0000000000..00232ec1b9
--- /dev/null
+++ b/package/kernel/mac80211/patches/subsys/331-wifi-mac80211-flush-queues-on-STA-removal.patch
@@ -0,0 +1,36 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Mon, 13 Mar 2023 11:42:12 +0100
+Subject: [PATCH] wifi: mac80211: flush queues on STA removal
+
+When we remove a station, we first make it unreachable,
+then we (must) remove its keys, and then remove the
+station itself. Depending on the hardware design, if
+we have hardware crypto at all, frames still sitting
+on hardware queues may then be transmitted without a
+valid key, possibly unencrypted or with a fixed key.
+
+Fix this by flushing the queues when removing stations
+so this cannot happen.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Reviewed-by: Greenman, Gregory <gregory.greenman@intel.com>
+---
+
+--- a/net/mac80211/sta_info.c
++++ b/net/mac80211/sta_info.c
+@@ -1271,6 +1271,14 @@ static void __sta_info_destroy_part2(str
+ WARN_ON_ONCE(ret);
+ }
+
++ /* Flush queues before removing keys, as that might remove them
++ * from hardware, and then depending on the offload method, any
++ * frames sitting on hardware queues might be sent out without
++ * any encryption at all.
++ */
++ if (local->ops->set_key)
++ ieee80211_flush_queues(local, sta->sdata, false);
++
+ /* now keys can no longer be reached */
+ ieee80211_free_sta_keys(local, sta);
+
diff --git a/package/kernel/mac80211/patches/subsys/332-wifi-iwlwifi-mvm-support-flush-on-AP-interfaces.patch b/package/kernel/mac80211/patches/subsys/332-wifi-iwlwifi-mvm-support-flush-on-AP-interfaces.patch
new file mode 100644
index 0000000000..3c31dfeddc
--- /dev/null
+++ b/package/kernel/mac80211/patches/subsys/332-wifi-iwlwifi-mvm-support-flush-on-AP-interfaces.patch
@@ -0,0 +1,34 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Mon, 13 Mar 2023 12:02:58 +0100
+Subject: [PATCH] wifi: iwlwifi: mvm: support flush on AP interfaces
+
+Support TX flush on AP interfaces so that we will do a
+proper flush for frames on the queue before keys are
+removed.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Reviewed-by: Greenman, Gregory <gregory.greenman@intel.com>
+---
+
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+@@ -4854,9 +4854,6 @@ static void iwl_mvm_mac_flush(struct iee
+ return;
+ }
+
+- if (vif->type != NL80211_IFTYPE_STATION)
+- return;
+-
+ /* Make sure we're done with the deferred traffic before flushing */
+ flush_work(&mvm->add_stream_wk);
+
+@@ -4874,9 +4871,6 @@ static void iwl_mvm_mac_flush(struct iee
+ if (mvmsta->vif != vif)
+ continue;
+
+- /* make sure only TDLS peers or the AP are flushed */
+- WARN_ON(i != mvmvif->ap_sta_id && !sta->tdls);
+-
+ if (drop) {
+ if (iwl_mvm_flush_sta(mvm, mvmsta, false))
+ IWL_ERR(mvm, "flush request fail\n");
diff --git a/package/kernel/mac80211/patches/subsys/333-wifi-mac80211-add-flush_sta-method.patch b/package/kernel/mac80211/patches/subsys/333-wifi-mac80211-add-flush_sta-method.patch
new file mode 100644
index 0000000000..300a2b65c6
--- /dev/null
+++ b/package/kernel/mac80211/patches/subsys/333-wifi-mac80211-add-flush_sta-method.patch
@@ -0,0 +1,91 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Mon, 13 Mar 2023 11:53:51 +0100
+Subject: [PATCH] wifi: mac80211: add flush_sta method
+
+Some drivers like iwlwifi might have per-STA queues, so we
+may want to flush/drop just those queues rather than all
+when removing a station. Add a separate method for that.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Reviewed-by: Greenman, Gregory <gregory.greenman@intel.com>
+---
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -3922,6 +3922,10 @@ struct ieee80211_prep_tx_info {
+ * Note that vif can be NULL.
+ * The callback can sleep.
+ *
++ * @flush_sta: Flush or drop all pending frames from the hardware queue(s) for
++ * the given station, as it's about to be removed.
++ * The callback can sleep.
++ *
+ * @channel_switch: Drivers that need (or want) to offload the channel
+ * switch operation for CSAs received from the AP may implement this
+ * callback. They must then call ieee80211_chswitch_done() to indicate
+@@ -4376,6 +4380,8 @@ struct ieee80211_ops {
+ #endif
+ void (*flush)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u32 queues, bool drop);
++ void (*flush_sta)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
++ struct ieee80211_sta *sta);
+ void (*channel_switch)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_channel_switch *ch_switch);
+--- a/net/mac80211/driver-ops.h
++++ b/net/mac80211/driver-ops.h
+@@ -617,6 +617,21 @@ static inline void drv_flush(struct ieee
+ trace_drv_return_void(local);
+ }
+
++static inline void drv_flush_sta(struct ieee80211_local *local,
++ struct ieee80211_sub_if_data *sdata,
++ struct sta_info *sta)
++{
++ might_sleep();
++
++ if (sdata && !check_sdata_in_driver(sdata))
++ return;
++
++ trace_drv_flush_sta(local, sdata, &sta->sta);
++ if (local->ops->flush_sta)
++ local->ops->flush_sta(&local->hw, &sdata->vif, &sta->sta);
++ trace_drv_return_void(local);
++}
++
+ static inline void drv_channel_switch(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel_switch *ch_switch)
+--- a/net/mac80211/sta_info.c
++++ b/net/mac80211/sta_info.c
+@@ -1276,8 +1276,12 @@ static void __sta_info_destroy_part2(str
+ * frames sitting on hardware queues might be sent out without
+ * any encryption at all.
+ */
+- if (local->ops->set_key)
+- ieee80211_flush_queues(local, sta->sdata, false);
++ if (local->ops->set_key) {
++ if (local->ops->flush_sta)
++ drv_flush_sta(local, sta->sdata, sta);
++ else
++ ieee80211_flush_queues(local, sta->sdata, false);
++ }
+
+ /* now keys can no longer be reached */
+ ieee80211_free_sta_keys(local, sta);
+--- a/net/mac80211/trace.h
++++ b/net/mac80211/trace.h
+@@ -1177,6 +1177,13 @@ TRACE_EVENT(drv_flush,
+ )
+ );
+
++DEFINE_EVENT(sta_event, drv_flush_sta,
++ TP_PROTO(struct ieee80211_local *local,
++ struct ieee80211_sub_if_data *sdata,
++ struct ieee80211_sta *sta),
++ TP_ARGS(local, sdata, sta)
++);
++
+ TRACE_EVENT(drv_channel_switch,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
diff --git a/package/kernel/mac80211/patches/subsys/334-wifi-iwlwifi-mvm-support-new-flush_sta-method.patch b/package/kernel/mac80211/patches/subsys/334-wifi-iwlwifi-mvm-support-new-flush_sta-method.patch
new file mode 100644
index 0000000000..18f39d505f
--- /dev/null
+++ b/package/kernel/mac80211/patches/subsys/334-wifi-iwlwifi-mvm-support-new-flush_sta-method.patch
@@ -0,0 +1,53 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Mon, 13 Mar 2023 12:05:35 +0100
+Subject: [PATCH] wifi: iwlwifi: mvm: support new flush_sta method
+
+For iwlwifi this is simple to implement, and on newer hardware
+it's an improvement since we have per-station queues.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Reviewed-by: Greenman, Gregory <gregory.greenman@intel.com>
+---
+
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+@@ -4890,6 +4890,31 @@ static void iwl_mvm_mac_flush(struct iee
+ iwl_trans_wait_tx_queues_empty(mvm->trans, msk);
+ }
+
++static void iwl_mvm_mac_flush_sta(struct ieee80211_hw *hw,
++ struct ieee80211_vif *vif,
++ struct ieee80211_sta *sta)
++{
++ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
++ int i;
++
++ mutex_lock(&mvm->mutex);
++ for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {
++ struct iwl_mvm_sta *mvmsta;
++ struct ieee80211_sta *tmp;
++
++ tmp = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
++ lockdep_is_held(&mvm->mutex));
++ if (tmp != sta)
++ continue;
++
++ mvmsta = iwl_mvm_sta_from_mac80211(sta);
++
++ if (iwl_mvm_flush_sta(mvm, mvmsta, false))
++ IWL_ERR(mvm, "flush request fail\n");
++ }
++ mutex_unlock(&mvm->mutex);
++}
++
+ static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
+ struct survey_info *survey)
+ {
+@@ -5417,6 +5442,7 @@ const struct ieee80211_ops iwl_mvm_hw_op
+ .mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx,
+ .mgd_protect_tdls_discover = iwl_mvm_mac_mgd_protect_tdls_discover,
+ .flush = iwl_mvm_mac_flush,
++ .flush_sta = iwl_mvm_mac_flush_sta,
+ .sched_scan_start = iwl_mvm_mac_sched_scan_start,
+ .sched_scan_stop = iwl_mvm_mac_sched_scan_stop,
+ .set_key = iwl_mvm_mac_set_key,