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
Backport of 6bf77c5803
BugzId: 74370
This commit is contained in:
parent
3ed0054c18
commit
c0fbce1571
|
|
@ -1,29 +1,29 @@
|
|||
From 3ec00c7616f20083d3775e28bcf76b660838e9b3 Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Walther <patrick.walther@netmodule.com>
|
||||
Date: Fri, 24 Jul 2020 18:56:44 +0200
|
||||
Subject: [PATCH] backport of netmodule patches from openwrt
|
||||
commit 775f8efe32011d6efc55d383a1c88fb173c80246
|
||||
Author: Patrick Walther <patrick.walther@netmodule.com>
|
||||
Date: Fri Jul 24 18:56:44 2020 +0200
|
||||
|
||||
---
|
||||
drivers/net/wireless/ath/ath10k/mac.c | 2 +-
|
||||
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 | 13 +++----
|
||||
drivers/net/wireless/ti/wlcore/cmd.h | 3 +-
|
||||
drivers/net/wireless/ti/wlcore/conf.h | 3 ++
|
||||
drivers/net/wireless/ti/wlcore/init.c | 22 +++++++++---
|
||||
drivers/net/wireless/ti/wlcore/main.c | 58 ++++++++++++++++++++-----------
|
||||
drivers/net/wireless/ti/wlcore/wlcore_i.h | 1 +
|
||||
include/net/cfg80211.h | 10 ++++--
|
||||
include/net/mac80211.h | 7 ++--
|
||||
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, 167 insertions(+), 57 deletions(-)
|
||||
backport of netmodule patches from openwrt
|
||||
|
||||
%% original patch: 0009-backport-of-netmodule-patches-from-openwrt.patch
|
||||
|
||||
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/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
|
||||
index 7946d3b..ba289ad 100644
|
||||
|
|
@ -51,6 +51,263 @@ index d7435c9..57ec879 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..0b890db 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 b647a32..c3892a9 100644
|
||||
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
|
||||
@@ -1460,7 +1460,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 015fe02..9b2e6d8 100644
|
||||
--- a/drivers/net/wireless/ath/ath9k/hw.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/hw.h
|
||||
@@ -830,6 +830,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 17418f9..5efd45c 100644
|
||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
||||
@@ -831,12 +831,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);
|
||||
|
||||
@@ -904,6 +972,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;
|
||||
@@ -1546,12 +1622,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;
|
||||
}
|
||||
@@ -1713,6 +1788,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)
|
||||
@@ -1742,7 +1823,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 e263400..c242f00 100644
|
||||
--- a/drivers/net/wireless/ath/regd.c
|
||||
|
|
@ -415,7 +672,7 @@ index 6fab60b..eefae3f 100644
|
|||
|
||||
enum wl12xx_flags {
|
||||
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
|
||||
index 8099b10..4849bab 100644
|
||||
index 75ecfeb..3b4b4e2 100644
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -112,6 +112,7 @@ enum ieee80211_channel_flags {
|
||||
|
|
|
|||
Loading…
Reference in New Issue