mirror of
https://github.com/opnsense/src.git
synced 2026-02-16 00:58:21 -05:00
net80211: prevent plaintext injection by A-MSDU RFC1042/EAPOL frames
No longer accept plaintext A-MSDU frames that start with an RFC1042 header with EtherType EAPOL. This is done by only accepting EAPOL packets that are included in non-aggregated 802.11 frames. Note that before this patch, FreeBSD also only accepted EAPOL frames that are sent in a non-aggregated 802.11 frame due to bugs in processing EAPOL packets inside A-MSDUs. In other words, compatibility with legitimate devices remains the same. This relates to section 6.5 in the 2021 Usenix "FragAttacks" (Fragment and Forge: Breaking Wi-Fi Through Frame Aggregation and Fragmentation) paper. Submitted by: Mathy Vanhoef (Mathy.Vanhoef kuleuven.be) Security: CVE-2020-26144 PR: 256120 MFC after: 7 days Differential Revision: https://reviews.freebsd.org/D30665
This commit is contained in:
parent
f024bdf115
commit
ffc19cf52d
4 changed files with 48 additions and 24 deletions
|
|
@ -571,7 +571,10 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m,
|
|||
IEEE80211_NODE_STAT(ni, rx_decap);
|
||||
goto err;
|
||||
}
|
||||
eh = mtod(m, struct ether_header *);
|
||||
if (!(qos & IEEE80211_QOS_AMSDU))
|
||||
eh = mtod(m, struct ether_header *);
|
||||
else
|
||||
eh = NULL;
|
||||
if (!ieee80211_node_is_authorized(ni)) {
|
||||
/*
|
||||
* Deny any non-PAE frames received prior to
|
||||
|
|
@ -581,11 +584,13 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m,
|
|||
* the port is not marked authorized by the
|
||||
* authenticator until the handshake has completed.
|
||||
*/
|
||||
if (eh->ether_type != htons(ETHERTYPE_PAE)) {
|
||||
if (eh == NULL ||
|
||||
eh->ether_type != htons(ETHERTYPE_PAE)) {
|
||||
IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
|
||||
eh->ether_shost, "data",
|
||||
"unauthorized port: ether type 0x%x len %u",
|
||||
eh->ether_type, m->m_pkthdr.len);
|
||||
ni->ni_macaddr, "data", "unauthorized or "
|
||||
"unknown port: ether type 0x%x len %u",
|
||||
eh == NULL ? -1 : eh->ether_type,
|
||||
m->m_pkthdr.len);
|
||||
vap->iv_stats.is_rx_unauth++;
|
||||
IEEE80211_NODE_STAT(ni, rx_unauth);
|
||||
goto err;
|
||||
|
|
@ -598,7 +603,8 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m,
|
|||
if ((vap->iv_flags & IEEE80211_F_DROPUNENC) &&
|
||||
((has_decrypted == 0) && (m->m_flags & M_WEP) == 0) &&
|
||||
(is_hw_decrypted == 0) &&
|
||||
eh->ether_type != htons(ETHERTYPE_PAE)) {
|
||||
(eh == NULL ||
|
||||
eh->ether_type != htons(ETHERTYPE_PAE))) {
|
||||
/*
|
||||
* Drop unencrypted frames.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -757,7 +757,10 @@ hostap_input(struct ieee80211_node *ni, struct mbuf *m,
|
|||
IEEE80211_NODE_STAT(ni, rx_decap);
|
||||
goto err;
|
||||
}
|
||||
eh = mtod(m, struct ether_header *);
|
||||
if (!(qos & IEEE80211_QOS_AMSDU))
|
||||
eh = mtod(m, struct ether_header *);
|
||||
else
|
||||
eh = NULL;
|
||||
if (!ieee80211_node_is_authorized(ni)) {
|
||||
/*
|
||||
* Deny any non-PAE frames received prior to
|
||||
|
|
@ -767,11 +770,13 @@ hostap_input(struct ieee80211_node *ni, struct mbuf *m,
|
|||
* the port is not marked authorized by the
|
||||
* authenticator until the handshake has completed.
|
||||
*/
|
||||
if (eh->ether_type != htons(ETHERTYPE_PAE)) {
|
||||
if (eh == NULL ||
|
||||
eh->ether_type != htons(ETHERTYPE_PAE)) {
|
||||
IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
|
||||
eh->ether_shost, "data",
|
||||
"unauthorized port: ether type 0x%x len %u",
|
||||
eh->ether_type, m->m_pkthdr.len);
|
||||
ni->ni_macaddr, "data", "unauthorized or "
|
||||
"unknown port: ether type 0x%x len %u",
|
||||
eh == NULL ? -1 : eh->ether_type,
|
||||
m->m_pkthdr.len);
|
||||
vap->iv_stats.is_rx_unauth++;
|
||||
IEEE80211_NODE_STAT(ni, rx_unauth);
|
||||
goto err;
|
||||
|
|
@ -784,7 +789,8 @@ hostap_input(struct ieee80211_node *ni, struct mbuf *m,
|
|||
if ((vap->iv_flags & IEEE80211_F_DROPUNENC) &&
|
||||
((has_decrypted == 0) && (m->m_flags & M_WEP) == 0) &&
|
||||
(is_hw_decrypted == 0) &&
|
||||
eh->ether_type != htons(ETHERTYPE_PAE)) {
|
||||
(eh == NULL ||
|
||||
eh->ether_type != htons(ETHERTYPE_PAE))) {
|
||||
/*
|
||||
* Drop unencrypted frames.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -840,7 +840,10 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m,
|
|||
IEEE80211_NODE_STAT(ni, rx_decap);
|
||||
goto err;
|
||||
}
|
||||
eh = mtod(m, struct ether_header *);
|
||||
if (!(qos & IEEE80211_QOS_AMSDU))
|
||||
eh = mtod(m, struct ether_header *);
|
||||
else
|
||||
eh = NULL;
|
||||
if (!ieee80211_node_is_authorized(ni)) {
|
||||
/*
|
||||
* Deny any non-PAE frames received prior to
|
||||
|
|
@ -850,11 +853,13 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m,
|
|||
* the port is not marked authorized by the
|
||||
* authenticator until the handshake has completed.
|
||||
*/
|
||||
if (eh->ether_type != htons(ETHERTYPE_PAE)) {
|
||||
if (eh == NULL ||
|
||||
eh->ether_type != htons(ETHERTYPE_PAE)) {
|
||||
IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
|
||||
eh->ether_shost, "data",
|
||||
"unauthorized port: ether type 0x%x len %u",
|
||||
eh->ether_type, m->m_pkthdr.len);
|
||||
ni->ni_macaddr, "data", "unauthorized or "
|
||||
"unknown port: ether type 0x%x len %u",
|
||||
eh == NULL ? -1 : eh->ether_type,
|
||||
m->m_pkthdr.len);
|
||||
vap->iv_stats.is_rx_unauth++;
|
||||
IEEE80211_NODE_STAT(ni, rx_unauth);
|
||||
goto err;
|
||||
|
|
@ -867,7 +872,8 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m,
|
|||
if ((vap->iv_flags & IEEE80211_F_DROPUNENC) &&
|
||||
((has_decrypted == 0) && (m->m_flags & M_WEP) == 0) &&
|
||||
(is_hw_decrypted == 0) &&
|
||||
eh->ether_type != htons(ETHERTYPE_PAE)) {
|
||||
(eh == NULL ||
|
||||
eh->ether_type != htons(ETHERTYPE_PAE))) {
|
||||
/*
|
||||
* Drop unencrypted frames.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -634,7 +634,10 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m,
|
|||
IEEE80211_NODE_STAT(ni, rx_decap);
|
||||
goto err;
|
||||
}
|
||||
eh = mtod(m, struct ether_header *);
|
||||
if (!(qos & IEEE80211_QOS_AMSDU))
|
||||
eh = mtod(m, struct ether_header *);
|
||||
else
|
||||
eh = NULL;
|
||||
if (!ieee80211_node_is_authorized(ni)) {
|
||||
/*
|
||||
* Deny any non-PAE frames received prior to
|
||||
|
|
@ -644,11 +647,13 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m,
|
|||
* the port is not marked authorized by the
|
||||
* authenticator until the handshake has completed.
|
||||
*/
|
||||
if (eh->ether_type != htons(ETHERTYPE_PAE)) {
|
||||
if (eh == NULL ||
|
||||
eh->ether_type != htons(ETHERTYPE_PAE)) {
|
||||
IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
|
||||
eh->ether_shost, "data",
|
||||
"unauthorized port: ether type 0x%x len %u",
|
||||
eh->ether_type, m->m_pkthdr.len);
|
||||
ni->ni_macaddr, "data", "unauthorized or "
|
||||
"unknown port: ether type 0x%x len %u",
|
||||
eh == NULL ? -1 : eh->ether_type,
|
||||
m->m_pkthdr.len);
|
||||
vap->iv_stats.is_rx_unauth++;
|
||||
IEEE80211_NODE_STAT(ni, rx_unauth);
|
||||
goto err;
|
||||
|
|
@ -661,7 +666,8 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m,
|
|||
if ((vap->iv_flags & IEEE80211_F_DROPUNENC) &&
|
||||
((has_decrypted == 0) && (m->m_flags & M_WEP) == 0) &&
|
||||
(is_hw_decrypted == 0) &&
|
||||
eh->ether_type != htons(ETHERTYPE_PAE)) {
|
||||
(eh == NULL ||
|
||||
eh->ether_type != htons(ETHERTYPE_PAE))) {
|
||||
/*
|
||||
* Drop unencrypted frames.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in a new issue