On Sun, Jan 31, 2016 at 03:14:46PM +0100, Mark Kettenis wrote:
> I think you should add a TCHECK somewhere at the top for the qos frame
> size otherwise this might look beyond the end of the buffer for
> specially crafted frames.

Oh yes, indeed.

Index: print-802_11.c
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/print-802_11.c,v
retrieving revision 1.28
diff -u -p -r1.28 print-802_11.c
--- print-802_11.c      12 Jan 2016 09:28:10 -0000      1.28
+++ print-802_11.c      31 Jan 2016 19:56:07 -0000
@@ -153,14 +153,25 @@ int
 ieee80211_data(struct ieee80211_frame *wh, u_int len)
 {
        u_int8_t *t = (u_int8_t *)wh;
-       struct ieee80211_frame_addr4 *w4;
        u_int datalen;
        int data = !(wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_NODATA);
+       int hasqos = ((wh->i_fc[0] &
+           (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) ==
+           (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS));
        u_char *esrc = NULL, *edst = NULL;
 
-       TCHECK(*wh);
-       t += sizeof(struct ieee80211_frame);
-       datalen = len - sizeof(struct ieee80211_frame);
+       if (hasqos) {
+               struct ieee80211_qosframe *wq;
+
+               wq = (struct ieee80211_qosframe *) wh;
+               TCHECK(*wq);
+               t += sizeof(*wq);
+               datalen = len - sizeof(*wq);
+       } else {
+               TCHECK(*wh);
+               t += sizeof(*wh);
+               datalen = len - sizeof(*wh);
+       }
 
        switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
        case IEEE80211_FC1_DIR_TODS:
@@ -176,12 +187,25 @@ ieee80211_data(struct ieee80211_frame *w
                edst = wh->i_addr1;
                break;
        case IEEE80211_FC1_DIR_DSTODS:
-               w4 = (struct ieee80211_frame_addr4 *) wh;
-               TCHECK(*w4);
-               t = (u_int8_t *) (w4 + 1);
-               datalen = len - sizeof(*w4);
-               esrc = w4->i_addr4;
-               edst = w4->i_addr3;
+               if (hasqos) {
+                       struct ieee80211_qosframe_addr4 *w4;
+
+                       w4 = (struct ieee80211_qosframe_addr4 *) wh;
+                       TCHECK(*w4);
+                       t = (u_int8_t *) (w4 + 1);
+                       datalen = len - sizeof(*w4);
+                       esrc = w4->i_addr4;
+                       edst = w4->i_addr3;
+               } else {
+                       struct ieee80211_frame_addr4 *w4;
+
+                       w4 = (struct ieee80211_frame_addr4 *) wh;
+                       TCHECK(*w4);
+                       t = (u_int8_t *) (w4 + 1);
+                       datalen = len - sizeof(*w4);
+                       esrc = w4->i_addr4;
+                       edst = w4->i_addr3;
+               }
                break;
        }
 

Reply via email to