On Wed, Feb 03, 2016 at 05:25:55PM +0100, Mark Kettenis wrote:
> > Date: Wed, 3 Feb 2016 17:03:46 +0100
> > From: Stefan Sperling <[email protected]>
> > 
> > This allows tcpdump to see all control frames with iwn(4).
> 
> Hmm, the code below that does look inside the frame.  How do we
> guarantee it isn't looking at garbage or reading beyond the end of the
> buffer?

Eeek, quite right. How about this?

Index: if_iwn.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwn.c,v
retrieving revision 1.158
diff -u -p -r1.158 if_iwn.c
--- if_iwn.c    25 Jan 2016 11:27:11 -0000      1.158
+++ if_iwn.c    3 Feb 2016 17:44:43 -0000
@@ -2008,7 +2008,15 @@ iwn_rx_done(struct iwn_softc *sc, struct
                return;
        }
        /* Discard frames that are too short. */
-       if (len < sizeof (*wh)) {
+       if (ic->ic_opmode == IEEE80211_M_MONITOR) {
+               /* Allow control frames in monitor mode. */
+               if (len < sizeof (struct ieee80211_frame_cts)) {
+                       DPRINTF(("frame too short: %d\n", len));
+                       ic->ic_stats.is_rx_tooshort++;
+                       ifp->if_ierrors++;
+                       return;
+               }
+       } else if (len < sizeof (*wh)) {
                DPRINTF(("frame too short: %d\n", len));
                ic->ic_stats.is_rx_tooshort++;
                ifp->if_ierrors++;
@@ -2058,12 +2066,24 @@ iwn_rx_done(struct iwn_softc *sc, struct
        m->m_data = head;
        m->m_pkthdr.len = m->m_len = len;
 
-       /* Grab a reference to the source node. */
+       /* 
+        * Grab a reference to the source node. Note that control frames are
+        * shorter than struct ieee80211_frame but ieee80211_find_rxnode()
+        * is being careful about control frames.
+        */
        wh = mtod(m, struct ieee80211_frame *);
+       if (len < sizeof (*wh) &&
+          (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) {
+               ic->ic_stats.is_rx_tooshort++;
+               ifp->if_ierrors++;
+               m_freem(m);
+               return;
+       }
        ni = ieee80211_find_rxnode(ic, wh);
 
        rxi.rxi_flags = 0;
-       if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
+       if (((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL)
+           && (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
            !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
            (ni->ni_flags & IEEE80211_NODE_RXPROT) &&
            ni->ni_pairwise_key.k_cipher == IEEE80211_CIPHER_CCMP) {

Reply via email to