Commit 9acc54be authored by Johannes Berg's avatar Johannes Berg

mac80211: check PN correctly for GCMP-encrypted fragmented MPDUs

Just like for CCMP we need to check that for GCMP the fragments
have PNs that increment by one; the spec was updated to fix this
security issue and now has the following text:

	The receiver shall discard MSDUs and MMPDUs whose constituent
	MPDU PN values are not incrementing in steps of 1.

Adapt the code for CCMP to work for GCMP as well, luckily the
relevant fields already alias each other so no code duplication
is needed (just check the aliasing with BUILD_BUG_ON.)

Cc: stable@vger.kernel.org
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent b8607152
...@@ -92,7 +92,7 @@ struct ieee80211_fragment_entry { ...@@ -92,7 +92,7 @@ struct ieee80211_fragment_entry {
u16 extra_len; u16 extra_len;
u16 last_frag; u16 last_frag;
u8 rx_queue; u8 rx_queue;
bool ccmp; /* Whether fragments were encrypted with CCMP */ bool check_sequential_pn; /* needed for CCMP/GCMP */
u8 last_pn[6]; /* PN of the last fragment if CCMP was used */ u8 last_pn[6]; /* PN of the last fragment if CCMP was used */
}; };
......
...@@ -1753,7 +1753,7 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, ...@@ -1753,7 +1753,7 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
entry->seq = seq; entry->seq = seq;
entry->rx_queue = rx_queue; entry->rx_queue = rx_queue;
entry->last_frag = frag; entry->last_frag = frag;
entry->ccmp = 0; entry->check_sequential_pn = false;
entry->extra_len = 0; entry->extra_len = 0;
return entry; return entry;
...@@ -1849,15 +1849,27 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) ...@@ -1849,15 +1849,27 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
rx->seqno_idx, &(rx->skb)); rx->seqno_idx, &(rx->skb));
if (rx->key && if (rx->key &&
(rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP || (rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP ||
rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256) && rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256 ||
rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP ||
rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP_256) &&
ieee80211_has_protected(fc)) { ieee80211_has_protected(fc)) {
int queue = rx->security_idx; int queue = rx->security_idx;
/* Store CCMP PN so that we can verify that the next
* fragment has a sequential PN value. */ /* Store CCMP/GCMP PN so that we can verify that the
entry->ccmp = 1; * next fragment has a sequential PN value.
*/
entry->check_sequential_pn = true;
memcpy(entry->last_pn, memcpy(entry->last_pn,
rx->key->u.ccmp.rx_pn[queue], rx->key->u.ccmp.rx_pn[queue],
IEEE80211_CCMP_PN_LEN); IEEE80211_CCMP_PN_LEN);
BUILD_BUG_ON(offsetof(struct ieee80211_key,
u.ccmp.rx_pn) !=
offsetof(struct ieee80211_key,
u.gcmp.rx_pn));
BUILD_BUG_ON(sizeof(rx->key->u.ccmp.rx_pn[queue]) !=
sizeof(rx->key->u.gcmp.rx_pn[queue]));
BUILD_BUG_ON(IEEE80211_CCMP_PN_LEN !=
IEEE80211_GCMP_PN_LEN);
} }
return RX_QUEUED; return RX_QUEUED;
} }
...@@ -1872,15 +1884,21 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) ...@@ -1872,15 +1884,21 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
return RX_DROP_MONITOR; return RX_DROP_MONITOR;
} }
/* Verify that MPDUs within one MSDU have sequential PN values. /* "The receiver shall discard MSDUs and MMPDUs whose constituent
* (IEEE 802.11i, 8.3.3.4.5) */ * MPDU PN values are not incrementing in steps of 1."
if (entry->ccmp) { * see IEEE P802.11-REVmc/D5.0, 12.5.3.4.4, item d (for CCMP)
* and IEEE P802.11-REVmc/D5.0, 12.5.5.4.4, item d (for GCMP)
*/
if (entry->check_sequential_pn) {
int i; int i;
u8 pn[IEEE80211_CCMP_PN_LEN], *rpn; u8 pn[IEEE80211_CCMP_PN_LEN], *rpn;
int queue; int queue;
if (!rx->key || if (!rx->key ||
(rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP && (rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP &&
rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP_256)) rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP_256 &&
rx->key->conf.cipher != WLAN_CIPHER_SUITE_GCMP &&
rx->key->conf.cipher != WLAN_CIPHER_SUITE_GCMP_256))
return RX_DROP_UNUSABLE; return RX_DROP_UNUSABLE;
memcpy(pn, entry->last_pn, IEEE80211_CCMP_PN_LEN); memcpy(pn, entry->last_pn, IEEE80211_CCMP_PN_LEN);
for (i = IEEE80211_CCMP_PN_LEN - 1; i >= 0; i--) { for (i = IEEE80211_CCMP_PN_LEN - 1; i >= 0; i--) {
......
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