The branch main has been updated by bz:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=3dc7a1897e0bb9e4b529c01cb3f88e1c387af5e8

commit 3dc7a1897e0bb9e4b529c01cb3f88e1c387af5e8
Author:     Bjoern A. Zeeb <b...@freebsd.org>
AuthorDate: 2021-09-30 16:41:19 +0000
Commit:     Bjoern A. Zeeb <b...@freebsd.org>
CommitDate: 2021-10-22 10:42:06 +0000

    net80211: correct input_sta length checks and control frame handling
    
    Correct input_sta "assertion" checks.  CTS/ACK CTRL frames are shorter
    then sizeof(struct ieee80211_frame_min) and were thus running into the
    is_rx_tooshort error case.
    Use ieee80211_anyhdrsize() to handle this better but make sure we do
    at least have the first 2 octets needed for that.
    While here move the safety checks before any code which may not obey
    them later, just for good style.
    
    The non-scanning check further down assumes a frame format also not
    matching control frames.  For now skip the checks for control frames
    which allows us to deal with some of them at least now.
    
    Sponsored by:   The FreeBSD Foundation
    Obtained from:  20210906 wireless v0.91 code drop
    MFC after:      3 days
    Reviewed by:    adrian
    Differential Revision: https://reviews.freebsd.org/D32238
---
 sys/net80211/ieee80211_sta.c | 66 +++++++++++++++++++++++++-------------------
 1 file changed, 37 insertions(+), 29 deletions(-)

diff --git a/sys/net80211/ieee80211_sta.c b/sys/net80211/ieee80211_sta.c
index cd62266ab942..7ea6187332b1 100644
--- a/sys/net80211/ieee80211_sta.c
+++ b/sys/net80211/ieee80211_sta.c
@@ -552,6 +552,35 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m,
        int is_hw_decrypted = 0;
        int has_decrypted = 0;
 
+       KASSERT(ni != NULL, ("%s: null node, mbuf %p", __func__, m));
+
+       /* Early init in case of early error case. */
+       type = -1;
+
+       /*
+        * Bit of a cheat here, we use a pointer for a 3-address
+        * frame format but don't reference fields past outside
+        * ieee80211_frame_min (or other shorter frames) w/o first
+        * validating the data is present.
+        */
+       wh = mtod(m, struct ieee80211_frame *);
+
+       if (m->m_pkthdr.len < 2 || m->m_pkthdr.len < ieee80211_anyhdrsize(wh)) {
+               IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
+                   ni->ni_macaddr, NULL,
+                   "too short (1): len %u", m->m_pkthdr.len);
+               vap->iv_stats.is_rx_tooshort++;
+               goto err;
+       }
+       if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
+           IEEE80211_FC0_VERSION_0) {
+               IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
+                   ni->ni_macaddr, NULL, "wrong version, fc %02x:%02x",
+                   wh->i_fc[0], wh->i_fc[1]);
+               vap->iv_stats.is_rx_badversion++;
+               goto err;
+       }
+
        /*
         * Some devices do hardware decryption all the way through
         * to pretending the frame wasn't encrypted in the first place.
@@ -569,7 +598,6 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m,
                 * with the M_AMPDU_MPDU flag and we can bypass most of
                 * the normal processing.
                 */
-               wh = mtod(m, struct ieee80211_frame *);
                type = IEEE80211_FC0_TYPE_DATA;
                dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
                subtype = IEEE80211_FC0_SUBTYPE_QOS;
@@ -577,39 +605,19 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m,
                goto resubmit_ampdu;
        }
 
-       KASSERT(ni != NULL, ("null node"));
        ni->ni_inact = ni->ni_inact_reload;
 
-       type = -1;                      /* undefined */
-
-       if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_min)) {
-               IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
-                   ni->ni_macaddr, NULL,
-                   "too short (1): len %u", m->m_pkthdr.len);
-               vap->iv_stats.is_rx_tooshort++;
-               goto out;
-       }
-       /*
-        * Bit of a cheat here, we use a pointer for a 3-address
-        * frame format but don't reference fields past outside
-        * ieee80211_frame_min w/o first validating the data is
-        * present.
-        */
-       wh = mtod(m, struct ieee80211_frame *);
-
-       if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
-           IEEE80211_FC0_VERSION_0) {
-               IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
-                   ni->ni_macaddr, NULL, "wrong version, fc %02x:%02x",
-                   wh->i_fc[0], wh->i_fc[1]);
-               vap->iv_stats.is_rx_badversion++;
-               goto err;
-       }
-
        dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
        type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
        subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
-       if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
+       /*
+        * Control frames are not folowing the header scheme of data and mgmt
+        * frames so we do not apply extra checks here.
+        * We probably should do checks on RA (+TA) where available for those
+        * too, but for now do not drop them.
+        */
+       if (type != IEEE80211_FC0_TYPE_CTL &&
+           (ic->ic_flags & IEEE80211_F_SCAN) == 0) {
                bssid = wh->i_addr2;
                if (!IEEE80211_ADDR_EQ(bssid, ni->ni_bssid)) {
                        /* not interested in */

Reply via email to