Commit 5ab2ba93 authored by Sara Sharon's avatar Sara Sharon Committed by Luca Coelho

iwlwifi: mvm: fix security bug in PN checking

A previous patch allowed the same PN for packets originating from the
same AMSDU by copying PN only for the last packet in the series.

This however is bogus since we cannot assume the last frame will be
received on the same queue, and if it is received on a different ueue
we will end up not incrementing the PN and possibly let the next
packet to have the same PN and pass through.

Change the logic instead to driver explicitly indicate for the second
sub frame and on to be allowed to have the same PN as the first
subframe. Indicate it to mac80211 as well for the fallback queue.

Fixes: f1ae02b1 ("iwlwifi: mvm: allow same PN for de-aggregated AMSDU")
Signed-off-by: default avatarSara Sharon <sara.sharon@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent 7ac8ff95
...@@ -71,6 +71,7 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb, ...@@ -71,6 +71,7 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_rx_status *stats = IEEE80211_SKB_RXCB(skb); struct ieee80211_rx_status *stats = IEEE80211_SKB_RXCB(skb);
struct iwl_mvm_key_pn *ptk_pn; struct iwl_mvm_key_pn *ptk_pn;
int res;
u8 tid, keyidx; u8 tid, keyidx;
u8 pn[IEEE80211_CCMP_PN_LEN]; u8 pn[IEEE80211_CCMP_PN_LEN];
u8 *extiv; u8 *extiv;
...@@ -127,11 +128,12 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb, ...@@ -127,11 +128,12 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb,
pn[4] = extiv[1]; pn[4] = extiv[1];
pn[5] = extiv[0]; pn[5] = extiv[0];
if (memcmp(pn, ptk_pn->q[queue].pn[tid], res = memcmp(pn, ptk_pn->q[queue].pn[tid], IEEE80211_CCMP_PN_LEN);
IEEE80211_CCMP_PN_LEN) <= 0) if (res < 0)
return -1;
if (!res && !(stats->flag & RX_FLAG_ALLOW_SAME_PN))
return -1; return -1;
if (!(stats->flag & RX_FLAG_AMSDU_MORE))
memcpy(ptk_pn->q[queue].pn[tid], pn, IEEE80211_CCMP_PN_LEN); memcpy(ptk_pn->q[queue].pn[tid], pn, IEEE80211_CCMP_PN_LEN);
stats->flag |= RX_FLAG_PN_VALIDATED; stats->flag |= RX_FLAG_PN_VALIDATED;
...@@ -314,28 +316,21 @@ static void iwl_mvm_rx_csum(struct ieee80211_sta *sta, ...@@ -314,28 +316,21 @@ static void iwl_mvm_rx_csum(struct ieee80211_sta *sta,
} }
/* /*
* returns true if a packet outside BA session is a duplicate and * returns true if a packet is a duplicate and should be dropped.
* should be dropped * Updates AMSDU PN tracking info
*/ */
static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue, static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue,
struct ieee80211_rx_status *rx_status, struct ieee80211_rx_status *rx_status,
struct ieee80211_hdr *hdr, struct ieee80211_hdr *hdr,
struct iwl_rx_mpdu_desc *desc) struct iwl_rx_mpdu_desc *desc)
{ {
struct iwl_mvm_sta *mvm_sta; struct iwl_mvm_sta *mvm_sta;
struct iwl_mvm_rxq_dup_data *dup_data; struct iwl_mvm_rxq_dup_data *dup_data;
u8 baid, tid, sub_frame_idx; u8 tid, sub_frame_idx;
if (WARN_ON(IS_ERR_OR_NULL(sta))) if (WARN_ON(IS_ERR_OR_NULL(sta)))
return false; return false;
baid = (le32_to_cpu(desc->reorder_data) &
IWL_RX_MPDU_REORDER_BAID_MASK) >>
IWL_RX_MPDU_REORDER_BAID_SHIFT;
if (baid != IWL_RX_REORDER_DATA_INVALID_BAID)
return false;
mvm_sta = iwl_mvm_sta_from_mac80211(sta); mvm_sta = iwl_mvm_sta_from_mac80211(sta);
dup_data = &mvm_sta->dup_data[queue]; dup_data = &mvm_sta->dup_data[queue];
...@@ -365,6 +360,12 @@ static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue, ...@@ -365,6 +360,12 @@ static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue,
dup_data->last_sub_frame[tid] >= sub_frame_idx)) dup_data->last_sub_frame[tid] >= sub_frame_idx))
return true; return true;
/* Allow same PN as the first subframe for following sub frames */
if (dup_data->last_seq[tid] == hdr->seq_ctrl &&
sub_frame_idx > dup_data->last_sub_frame[tid] &&
desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU)
rx_status->flag |= RX_FLAG_ALLOW_SAME_PN;
dup_data->last_seq[tid] = hdr->seq_ctrl; dup_data->last_seq[tid] = hdr->seq_ctrl;
dup_data->last_sub_frame[tid] = sub_frame_idx; dup_data->last_sub_frame[tid] = sub_frame_idx;
...@@ -971,7 +972,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, ...@@ -971,7 +972,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
if (ieee80211_is_data(hdr->frame_control)) if (ieee80211_is_data(hdr->frame_control))
iwl_mvm_rx_csum(sta, skb, desc); iwl_mvm_rx_csum(sta, skb, desc);
if (iwl_mvm_is_nonagg_dup(sta, queue, rx_status, hdr, desc)) { if (iwl_mvm_is_dup(sta, queue, rx_status, hdr, desc)) {
kfree_skb(skb); kfree_skb(skb);
goto out; goto out;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment