From 6bf77c5803385d1174438545bcf897637765afaf Mon Sep 17 00:00:00 2001 From: Patrick Walther Date: Thu, 19 Aug 2021 18:16:37 +0200 Subject: [PATCH] FIX: [mac80211] CVE-2020-3702 ath9k patches [1/5] ath: Use safer key clearing with key cache entries [2/5] ath9k: Clear key cache explicitly on disabling hardware [3/5] ath: Export ath_hw_keysetmac() [4/5] ath: Modify ath_key_delete() to not need full key entry [5/5] ath9k: Postpone key cache entry deletion for TXQ frames reference it BugzId: 74370 --- .../mac80211/0009-netmodule-patches.patch | 406 +++++++++++++++--- 1 file changed, 345 insertions(+), 61 deletions(-) diff --git a/recipes-kernel/mac80211/mac80211/0009-netmodule-patches.patch b/recipes-kernel/mac80211/mac80211/0009-netmodule-patches.patch index 52b139e..8d209c1 100644 --- a/recipes-kernel/mac80211/mac80211/0009-netmodule-patches.patch +++ b/recipes-kernel/mac80211/mac80211/0009-netmodule-patches.patch @@ -1,35 +1,62 @@ -From 6e5ef0edd3782babdeb47e7cc7b67afd3b225d95 Mon Sep 17 00:00:00 2001 +From 7ddf76afb4aa795fa6ec60defe149b36abaa9e8b Mon Sep 17 00:00:00 2001 From: Patrick Walther Date: Mon, 22 Mar 2021 17:52:02 +0100 Subject: [PATCH] 0007 netmodule patches --- - drivers/net/wireless/ath/ath10k/htt_rx.c | 6 +++-- - drivers/net/wireless/ath/ath10k/mac.c | 40 ++++++++++++++++++++++++------- - drivers/net/wireless/ath/ath10k/pci.c | 2 +- - drivers/net/wireless/ath/regd.c | 2 +- - drivers/net/wireless/ath/regd.h | 3 ++- - drivers/net/wireless/ath/regd_common.h | 1 + - drivers/net/wireless/ti/wlcore/cmd.c | 7 ------ - drivers/net/wireless/ti/wlcore/cmd.h | 1 + - drivers/net/wireless/ti/wlcore/conf.h | 3 +++ - drivers/net/wireless/ti/wlcore/init.c | 22 +++++++++++++---- - drivers/net/wireless/ti/wlcore/main.c | 27 +++++++++++++++------ - include/net/cfg80211.h | 11 +++++++-- - include/net/mac80211.h | 8 +++++-- - include/uapi/linux/nl80211.h | 3 +++ - net/mac80211/cfg.c | 13 ++++++++++ - net/mac80211/main.c | 4 ++-- - net/wireless/core.c | 41 ++++++++++++++++++++++++++------ - net/wireless/nl80211.c | 13 ++++++++++ - net/wireless/reg.c | 23 ++++++++++++++---- - 19 files changed, 180 insertions(+), 50 deletions(-) + drivers/net/wireless/ath/ath.h | 3 +- + drivers/net/wireless/ath/ath10k/htt_rx.c | 6 +- + drivers/net/wireless/ath/ath10k/mac.c | 40 ++++++++--- + drivers/net/wireless/ath/ath10k/pci.c | 2 +- + drivers/net/wireless/ath/ath5k/mac80211-ops.c | 2 +- + drivers/net/wireless/ath/ath9k/htc_drv_main.c | 2 +- + drivers/net/wireless/ath/ath9k/hw.h | 1 + + drivers/net/wireless/ath/ath9k/main.c | 95 ++++++++++++++++++++++++++- + drivers/net/wireless/ath/key.c | 41 +++++++----- + drivers/net/wireless/ath/regd.c | 2 +- + drivers/net/wireless/ath/regd.h | 3 +- + drivers/net/wireless/ath/regd_common.h | 1 + + drivers/net/wireless/ti/wlcore/cmd.c | 7 -- + drivers/net/wireless/ti/wlcore/cmd.h | 1 + + drivers/net/wireless/ti/wlcore/conf.h | 3 + + drivers/net/wireless/ti/wlcore/init.c | 22 +++++-- + drivers/net/wireless/ti/wlcore/main.c | 28 ++++++-- + include/net/cfg80211.h | 11 +++- + include/net/mac80211.h | 8 ++- + include/uapi/linux/nl80211.h | 3 + + net/mac80211/cfg.c | 13 ++++ + net/mac80211/iface.c | 9 ++- + net/mac80211/main.c | 4 +- + net/wireless/core.c | 41 ++++++++++-- + net/wireless/nl80211.c | 13 ++++ + net/wireless/reg.c | 23 +++++-- + net/wireless/wext-compat.c | 3 +- + 27 files changed, 312 insertions(+), 75 deletions(-) +diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h +index 2a18e2e..bb30fd7 100644 +--- a/drivers/net/wireless/ath/ath.h ++++ b/drivers/net/wireless/ath/ath.h +@@ -198,12 +198,13 @@ struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, + bool ath_is_mybeacon(struct ath_common *common, struct ieee80211_hdr *hdr); + + void ath_hw_setbssidmask(struct ath_common *common); +-void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key); ++void ath_key_delete(struct ath_common *common, u8 hw_key_idx); + int ath_key_config(struct ath_common *common, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key); + bool ath_hw_keyreset(struct ath_common *common, u16 entry); ++bool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac); + void ath_hw_cycle_counters_update(struct ath_common *common); + int32_t ath_hw_get_listen_time(struct ath_common *common); + diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c -index 5c1af20..5f166bc 100644 +index 28ec3c5..9bb791c 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c -@@ -3683,8 +3683,10 @@ static void ath10k_fetch_10_2_tx_stats(struct ath10k *ar, u8 *data) +@@ -3864,8 +3864,10 @@ static void ath10k_fetch_10_2_tx_stats(struct ath10k *ar, u8 *data) spin_lock_bh(&ar->data_lock); peer = ath10k_peer_find_by_id(ar, peer_id); if (!peer || !peer->sta) { @@ -139,6 +166,263 @@ index a7b6b8c..dc8c753 100644 static unsigned int ath10k_pci_reset_mode = ATH10K_PCI_RESET_AUTO; module_param_named(irq_mode, ath10k_pci_irq_mode, uint, 0644); +diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c +index 47dd580..9b7cbe7 100644 +--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c ++++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c +@@ -516,7 +516,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + } + break; + case DISABLE_KEY: +- ath_key_delete(common, key); ++ ath_key_delete(common, key->hw_key_idx); + break; + default: + ret = -EINVAL; +diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c +index abe6411..0909814 100644 +--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c ++++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c +@@ -1461,7 +1461,7 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw, + } + break; + case DISABLE_KEY: +- ath_key_delete(common, key); ++ ath_key_delete(common, key->hw_key_idx); + break; + default: + ret = -EINVAL; +diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h +index 559609d..d152b4b 100644 +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -831,6 +831,7 @@ struct ath_hw { + struct ath9k_pacal_info pacal_info; + struct ar5416Stats stats; + struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES]; ++ DECLARE_BITMAP(pending_del_keymap, ATH_KEYMAX); + + enum ath9k_int imask; + u32 imrs2_reg; +diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c +index 093eafd..dbd33d7 100644 +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -833,12 +833,80 @@ exit: + ieee80211_free_txskb(hw, skb); + } + ++static bool ath9k_txq_list_has_key(struct list_head *txq_list, u32 keyix) ++{ ++ struct ath_buf *bf; ++ struct ieee80211_tx_info *txinfo; ++ struct ath_frame_info *fi; ++ ++ list_for_each_entry(bf, txq_list, list) { ++ if (bf->bf_state.stale || !bf->bf_mpdu) ++ continue; ++ ++ txinfo = IEEE80211_SKB_CB(bf->bf_mpdu); ++ fi = (struct ath_frame_info *)&txinfo->rate_driver_data[0]; ++ if (fi->keyix == keyix) ++ return true; ++ } ++ ++ return false; ++} ++ ++static bool ath9k_txq_has_key(struct ath_softc *sc, u32 keyix) ++{ ++ struct ath_hw *ah = sc->sc_ah; ++ int i; ++ struct ath_txq *txq; ++ bool key_in_use = false; ++ ++ for (i = 0; !key_in_use && i < ATH9K_NUM_TX_QUEUES; i++) { ++ if (!ATH_TXQ_SETUP(sc, i)) ++ continue; ++ txq = &sc->tx.txq[i]; ++ if (!txq->axq_depth) ++ continue; ++ if (!ath9k_hw_numtxpending(ah, txq->axq_qnum)) ++ continue; ++ ++ ath_txq_lock(sc, txq); ++ key_in_use = ath9k_txq_list_has_key(&txq->axq_q, keyix); ++ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { ++ int idx = txq->txq_tailidx; ++ ++ while (!key_in_use && ++ !list_empty(&txq->txq_fifo[idx])) { ++ key_in_use = ath9k_txq_list_has_key( ++ &txq->txq_fifo[idx], keyix); ++ INCR(idx, ATH_TXFIFO_DEPTH); ++ } ++ } ++ ath_txq_unlock(sc, txq); ++ } ++ ++ return key_in_use; ++} ++ ++static void ath9k_pending_key_del(struct ath_softc *sc, u8 keyix) ++{ ++ struct ath_hw *ah = sc->sc_ah; ++ struct ath_common *common = ath9k_hw_common(ah); ++ ++ if (!test_bit(keyix, ah->pending_del_keymap) || ++ ath9k_txq_has_key(sc, keyix)) ++ return; ++ ++ /* No more TXQ frames point to this key cache entry, so delete it. */ ++ clear_bit(keyix, ah->pending_del_keymap); ++ ath_key_delete(common, keyix); ++} ++ + static void ath9k_stop(struct ieee80211_hw *hw) + { + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + bool prev_idle; ++ int i; + + ath9k_deinit_channel_context(sc); + +@@ -906,6 +974,14 @@ static void ath9k_stop(struct ieee80211_hw *hw) + + spin_unlock_bh(&sc->sc_pcu_lock); + ++ for (i = 0; i < ATH_KEYMAX; i++) ++ ath9k_pending_key_del(sc, i); ++ ++ /* Clear key cache entries explicitly to get rid of any potentially ++ * remaining keys. ++ */ ++ ath9k_cmn_init_crypto(sc->sc_ah); ++ + ath9k_ps_restore(sc); + + sc->ps_idle = prev_idle; +@@ -1555,12 +1631,11 @@ static void ath9k_del_ps_key(struct ath_softc *sc, + { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_node *an = (struct ath_node *) sta->drv_priv; +- struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key }; + + if (!an->ps_key) + return; + +- ath_key_delete(common, &ps_key); ++ ath_key_delete(common, an->ps_key); + an->ps_key = 0; + an->key_idx[0] = 0; + } +@@ -1731,6 +1806,12 @@ static int ath9k_set_key(struct ieee80211_hw *hw, + if (sta) + an = (struct ath_node *)sta->drv_priv; + ++ /* Delete pending key cache entries if no more frames are pointing to ++ * them in TXQs. ++ */ ++ for (i = 0; i < ATH_KEYMAX; i++) ++ ath9k_pending_key_del(sc, i); ++ + switch (cmd) { + case SET_KEY: + if (sta) +@@ -1760,7 +1841,15 @@ static int ath9k_set_key(struct ieee80211_hw *hw, + } + break; + case DISABLE_KEY: +- ath_key_delete(common, key); ++ if (ath9k_txq_has_key(sc, key->hw_key_idx)) { ++ /* Delay key cache entry deletion until there are no ++ * remaining TXQ frames pointing to this entry. ++ */ ++ set_bit(key->hw_key_idx, sc->sc_ah->pending_del_keymap); ++ ath_hw_keysetmac(common, key->hw_key_idx, NULL); ++ } else { ++ ath_key_delete(common, key->hw_key_idx); ++ } + if (an) { + for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) { + if (an->key_idx[i] != key->hw_key_idx) +diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c +index 1816b4e..61b59a8 100644 +--- a/drivers/net/wireless/ath/key.c ++++ b/drivers/net/wireless/ath/key.c +@@ -84,8 +84,7 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry) + } + EXPORT_SYMBOL(ath_hw_keyreset); + +-static bool ath_hw_keysetmac(struct ath_common *common, +- u16 entry, const u8 *mac) ++bool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac) + { + u32 macHi, macLo; + u32 unicast_flag = AR_KEYTABLE_VALID; +@@ -125,6 +124,7 @@ static bool ath_hw_keysetmac(struct ath_common *common, + + return true; + } ++EXPORT_SYMBOL(ath_hw_keysetmac); + + static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, + const struct ath_keyval *k, +@@ -581,29 +581,38 @@ EXPORT_SYMBOL(ath_key_config); + /* + * Delete Key. + */ +-void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key) ++void ath_key_delete(struct ath_common *common, u8 hw_key_idx) + { +- ath_hw_keyreset(common, key->hw_key_idx); +- if (key->hw_key_idx < IEEE80211_WEP_NKID) ++ /* Leave CCMP and TKIP (main key) configured to avoid disabling ++ * encryption for potentially pending frames already in a TXQ with the ++ * keyix pointing to this key entry. Instead, only clear the MAC address ++ * to prevent RX processing from using this key cache entry. ++ */ ++ if (test_bit(hw_key_idx, common->ccmp_keymap) || ++ test_bit(hw_key_idx, common->tkip_keymap)) ++ ath_hw_keysetmac(common, hw_key_idx, NULL); ++ else ++ ath_hw_keyreset(common, hw_key_idx); ++ if (hw_key_idx < IEEE80211_WEP_NKID) + return; + +- clear_bit(key->hw_key_idx, common->keymap); +- clear_bit(key->hw_key_idx, common->ccmp_keymap); +- if (key->cipher != WLAN_CIPHER_SUITE_TKIP) ++ clear_bit(hw_key_idx, common->keymap); ++ clear_bit(hw_key_idx, common->ccmp_keymap); ++ if (!test_bit(hw_key_idx, common->tkip_keymap)) + return; + +- clear_bit(key->hw_key_idx + 64, common->keymap); ++ clear_bit(hw_key_idx + 64, common->keymap); + +- clear_bit(key->hw_key_idx, common->tkip_keymap); +- clear_bit(key->hw_key_idx + 64, common->tkip_keymap); ++ clear_bit(hw_key_idx, common->tkip_keymap); ++ clear_bit(hw_key_idx + 64, common->tkip_keymap); + + if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) { +- ath_hw_keyreset(common, key->hw_key_idx + 32); +- clear_bit(key->hw_key_idx + 32, common->keymap); +- clear_bit(key->hw_key_idx + 64 + 32, common->keymap); ++ ath_hw_keyreset(common, hw_key_idx + 32); ++ clear_bit(hw_key_idx + 32, common->keymap); ++ clear_bit(hw_key_idx + 64 + 32, common->keymap); + +- clear_bit(key->hw_key_idx + 32, common->tkip_keymap); +- clear_bit(key->hw_key_idx + 64 + 32, common->tkip_keymap); ++ clear_bit(hw_key_idx + 32, common->tkip_keymap); ++ clear_bit(hw_key_idx + 64 + 32, common->tkip_keymap); + } + } + EXPORT_SYMBOL(ath_key_delete); diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 0042ea9..f7b15cf 100644 --- a/drivers/net/wireless/ath/regd.c @@ -268,7 +552,7 @@ index 03b49ba..5275d6b 100644 rc.long_retry_limit = 10; rc.aflags = 0; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c -index b5e3a42..5cc837e 100644 +index b5e3a42..8fbff25 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -2271,13 +2271,15 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) @@ -321,7 +605,7 @@ index b5e3a42..5cc837e 100644 wl1271_debug(DEBUG_MAC80211, "mac80211 get_rssi"); mutex_lock(&wl->mutex); -@@ -6227,6 +6238,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) +@@ -6227,6 +6239,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, WL1271_CIPHER_SUITE_GEM, @@ -329,7 +613,7 @@ index b5e3a42..5cc837e 100644 }; /* The tx descriptor buffer */ -@@ -6290,6 +6302,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) +@@ -6290,6 +6303,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) WIPHY_FLAG_IBSS_RSN; wl->hw->wiphy->features |= NL80211_FEATURE_AP_SCAN; @@ -338,7 +622,7 @@ index b5e3a42..5cc837e 100644 /* make sure all our channels fit in the scanned_ch bitmask */ BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) + diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h -index 449df09..1acf10c 100644 +index 092156b..c70a04f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -129,6 +129,7 @@ enum ieee80211_channel_flags { @@ -476,6 +760,40 @@ index 272b433..2a30e87 100644 .set_wds_peer = ieee80211_set_wds_peer, .rfkill_poll = ieee80211_rfkill_poll, CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) +diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c +index bf305b2..7998620 100644 +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -47,7 +47,7 @@ static void ieee80211_iface_work(struct work_struct *work); + bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) + { + struct ieee80211_chanctx_conf *chanctx_conf; +- int power; ++ int power, max_power; + + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); +@@ -56,7 +56,7 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) + return false; + } + +- power = ieee80211_chandef_max_power(&chanctx_conf->def); ++ power = max_power = ieee80211_chandef_max_power(&chanctx_conf->def); + rcu_read_unlock(); + + if (sdata->user_power_level != IEEE80211_UNSET_POWER_LEVEL) +@@ -65,6 +65,11 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) + if (sdata->ap_power_level != IEEE80211_UNSET_POWER_LEVEL) + power = min(power, sdata->ap_power_level); + ++ if (sdata->local->user_antenna_gain > 0 && sdata->local->use_chanctx) { ++ max_power -= sdata->local->user_antenna_gain; ++ power = min(power, max_power); ++ } ++ + if (power != sdata->vif.bss_conf.txpower) { + sdata->vif.bss_conf.txpower = power; + ieee80211_hw_config(sdata->local, 0); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 44076fb..293bfec 100644 --- a/net/mac80211/main.c @@ -663,37 +981,3 @@ index 78f2927..4fa5b0d 100644 data->txpower.flags = IW_TXPOW_DBM; return 0; -diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c -index bf305b2..7998620 100644 ---- a/net/mac80211/iface.c -+++ b/net/mac80211/iface.c -@@ -47,7 +47,7 @@ static void ieee80211_iface_work(struct work_struct *work); - bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) - { - struct ieee80211_chanctx_conf *chanctx_conf; -- int power; -+ int power, max_power; - - rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); -@@ -56,7 +56,7 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) - return false; - } - -- power = ieee80211_chandef_max_power(&chanctx_conf->def); -+ power = max_power = ieee80211_chandef_max_power(&chanctx_conf->def); - rcu_read_unlock(); - - if (sdata->user_power_level != IEEE80211_UNSET_POWER_LEVEL) -@@ -65,6 +65,11 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) - if (sdata->ap_power_level != IEEE80211_UNSET_POWER_LEVEL) - power = min(power, sdata->ap_power_level); - -+ if (sdata->local->user_antenna_gain > 0 && sdata->local->use_chanctx) { -+ max_power -= sdata->local->user_antenna_gain; -+ power = min(power, max_power); -+ } -+ - if (power != sdata->vif.bss_conf.txpower) { - sdata->vif.bss_conf.txpower = power; - ieee80211_hw_config(sdata->local, 0);