Skip to content

Commit 9be4e0b

Browse files
guyharrisinfrastation
authored andcommitted
CVE-2017-13000/IEEE 802.15.4: Add more bounds checks.
While we're at it, add a bunch of macros for the frame control field's subfields, have the reserved frame types show the frame type value, use the same code path for processing source and destination addresses regardless of whether -v was specified (just leave out the addresses in non-verbose mode), and return the header length in all cases. This fixes a buffer over-read discovered by Forcepoint's security researchers Otto Airamo & Antti Levomäki. Add tests using the capture files supplied by the reporter(s).
1 parent b1928b4 commit 9be4e0b

6 files changed

+146
-100
lines changed

Diff for: print-802_15_4.c

+142-100
Original file line numberDiff line numberDiff line change
@@ -38,144 +38,186 @@ static const char *ftypes[] = {
3838
"Data", /* 1 */
3939
"ACK", /* 2 */
4040
"Command", /* 3 */
41-
"Reserved", /* 4 */
42-
"Reserved", /* 5 */
43-
"Reserved", /* 6 */
44-
"Reserved", /* 7 */
41+
"Reserved (0x4)", /* 4 */
42+
"Reserved (0x5)", /* 5 */
43+
"Reserved (0x6)", /* 6 */
44+
"Reserved (0x7)", /* 7 */
4545
};
4646

47-
static int
48-
extract_header_length(uint16_t fc)
49-
{
50-
int len = 0;
51-
52-
switch ((fc >> 10) & 0x3) {
53-
case 0x00:
54-
if (fc & (1 << 6)) /* intra-PAN with none dest addr */
55-
return -1;
56-
break;
57-
case 0x01:
58-
return -1;
59-
case 0x02:
60-
len += 4;
61-
break;
62-
case 0x03:
63-
len += 10;
64-
break;
65-
}
66-
67-
switch ((fc >> 14) & 0x3) {
68-
case 0x00:
69-
break;
70-
case 0x01:
71-
return -1;
72-
case 0x02:
73-
len += 4;
74-
break;
75-
case 0x03:
76-
len += 10;
77-
break;
78-
}
79-
80-
if (fc & (1 << 6)) {
81-
if (len < 2)
82-
return -1;
83-
len -= 2;
84-
}
85-
86-
return len;
87-
}
88-
47+
/*
48+
* Frame Control subfields.
49+
*/
50+
#define FC_FRAME_TYPE(fc) ((fc) & 0x7)
51+
#define FC_SECURITY_ENABLED 0x0008
52+
#define FC_FRAME_PENDING 0x0010
53+
#define FC_ACK_REQUEST 0x0020
54+
#define FC_PAN_ID_COMPRESSION 0x0040
55+
#define FC_DEST_ADDRESSING_MODE(fc) (((fc) >> 10) & 0x3)
56+
#define FC_FRAME_VERSION(fc) (((fc) >> 12) & 0x3)
57+
#define FC_SRC_ADDRESSING_MODE(fc) (((fc) >> 14) & 0x3)
58+
59+
#define FC_ADDRESSING_MODE_NONE 0x00
60+
#define FC_ADDRESSING_MODE_RESERVED 0x01
61+
#define FC_ADDRESSING_MODE_SHORT 0x02
62+
#define FC_ADDRESSING_MODE_LONG 0x03
8963

9064
u_int
9165
ieee802_15_4_if_print(netdissect_options *ndo,
9266
const struct pcap_pkthdr *h, const u_char *p)
9367
{
9468
u_int caplen = h->caplen;
95-
int hdrlen;
69+
u_int hdrlen;
9670
uint16_t fc;
9771
uint8_t seq;
72+
uint16_t panid = 0;
9873

9974
if (caplen < 3) {
100-
ND_PRINT((ndo, "[|802.15.4] %x", caplen));
75+
ND_PRINT((ndo, "[|802.15.4]"));
10176
return caplen;
10277
}
78+
hdrlen = 3;
10379

10480
fc = EXTRACT_LE_16BITS(p);
105-
hdrlen = extract_header_length(fc);
106-
10781
seq = EXTRACT_LE_8BITS(p + 2);
10882

10983
p += 3;
11084
caplen -= 3;
11185

112-
ND_PRINT((ndo,"IEEE 802.15.4 %s packet ", ftypes[fc & 0x7]));
86+
ND_PRINT((ndo,"IEEE 802.15.4 %s packet ", ftypes[FC_FRAME_TYPE(fc)]));
11387
if (ndo->ndo_vflag)
11488
ND_PRINT((ndo,"seq %02x ", seq));
115-
if (hdrlen == -1) {
116-
ND_PRINT((ndo,"invalid! "));
117-
return caplen;
118-
}
119-
120-
121-
if (!ndo->ndo_vflag) {
122-
p+= hdrlen;
123-
caplen -= hdrlen;
124-
} else {
125-
uint16_t panid = 0;
12689

127-
switch ((fc >> 10) & 0x3) {
128-
case 0x00:
90+
/*
91+
* Destination address and PAN ID, if present.
92+
*/
93+
switch (FC_DEST_ADDRESSING_MODE(fc)) {
94+
case FC_ADDRESSING_MODE_NONE:
95+
if (fc & FC_PAN_ID_COMPRESSION) {
96+
/*
97+
* PAN ID compression; this requires that both
98+
* the source and destination addresses be present,
99+
* but the destination address is missing.
100+
*/
101+
ND_PRINT((ndo, "[|802.15.4]"));
102+
return hdrlen;
103+
}
104+
if (ndo->ndo_vflag)
129105
ND_PRINT((ndo,"none "));
130-
break;
131-
case 0x01:
106+
break;
107+
case FC_ADDRESSING_MODE_RESERVED:
108+
if (ndo->ndo_vflag)
132109
ND_PRINT((ndo,"reserved destination addressing mode"));
133-
return 0;
134-
case 0x02:
135-
panid = EXTRACT_LE_16BITS(p);
136-
p += 2;
137-
ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p)));
138-
p += 2;
139-
break;
140-
case 0x03:
141-
panid = EXTRACT_LE_16BITS(p);
142-
p += 2;
143-
ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(ndo, p)));
144-
p += 8;
145-
break;
110+
return hdrlen;
111+
case FC_ADDRESSING_MODE_SHORT:
112+
if (caplen < 2) {
113+
ND_PRINT((ndo, "[|802.15.4]"));
114+
return hdrlen;
115+
}
116+
panid = EXTRACT_LE_16BITS(p);
117+
p += 2;
118+
caplen -= 2;
119+
hdrlen += 2;
120+
if (caplen < 2) {
121+
ND_PRINT((ndo, "[|802.15.4]"));
122+
return hdrlen;
146123
}
124+
if (ndo->ndo_vflag)
125+
ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p + 2)));
126+
p += 2;
127+
caplen -= 2;
128+
hdrlen += 2;
129+
break;
130+
case FC_ADDRESSING_MODE_LONG:
131+
if (caplen < 2) {
132+
ND_PRINT((ndo, "[|802.15.4]"));
133+
return hdrlen;
134+
}
135+
panid = EXTRACT_LE_16BITS(p);
136+
p += 2;
137+
caplen -= 2;
138+
hdrlen += 2;
139+
if (caplen < 8) {
140+
ND_PRINT((ndo, "[|802.15.4]"));
141+
return hdrlen;
142+
}
143+
if (ndo->ndo_vflag)
144+
ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(ndo, p + 2)));
145+
p += 8;
146+
caplen -= 8;
147+
hdrlen += 8;
148+
break;
149+
}
150+
if (ndo->ndo_vflag)
147151
ND_PRINT((ndo,"< "));
148152

149-
switch ((fc >> 14) & 0x3) {
150-
case 0x00:
153+
/*
154+
* Source address and PAN ID, if present.
155+
*/
156+
switch (FC_SRC_ADDRESSING_MODE(fc)) {
157+
case FC_ADDRESSING_MODE_NONE:
158+
if (ndo->ndo_vflag)
151159
ND_PRINT((ndo,"none "));
152-
break;
153-
case 0x01:
160+
break;
161+
case FC_ADDRESSING_MODE_RESERVED:
162+
if (ndo->ndo_vflag)
154163
ND_PRINT((ndo,"reserved source addressing mode"));
155-
return 0;
156-
case 0x02:
157-
if (!(fc & (1 << 6))) {
158-
panid = EXTRACT_LE_16BITS(p);
159-
p += 2;
164+
return 0;
165+
case FC_ADDRESSING_MODE_SHORT:
166+
if (!(fc & FC_PAN_ID_COMPRESSION)) {
167+
/*
168+
* The source PAN ID is not compressed out, so
169+
* fetch it. (Otherwise, we'll use the destination
170+
* PAN ID, fetched above.)
171+
*/
172+
if (caplen < 2) {
173+
ND_PRINT((ndo, "[|802.15.4]"));
174+
return hdrlen;
160175
}
161-
ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p)));
176+
panid = EXTRACT_LE_16BITS(p);
162177
p += 2;
163-
break;
164-
case 0x03:
165-
if (!(fc & (1 << 6))) {
166-
panid = EXTRACT_LE_16BITS(p);
167-
p += 2;
178+
caplen -= 2;
179+
hdrlen += 2;
180+
}
181+
if (caplen < 2) {
182+
ND_PRINT((ndo, "[|802.15.4]"));
183+
return hdrlen;
184+
}
185+
if (ndo->ndo_vflag)
186+
ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p)));
187+
p += 2;
188+
caplen -= 2;
189+
hdrlen += 2;
190+
break;
191+
case FC_ADDRESSING_MODE_LONG:
192+
if (!(fc & FC_PAN_ID_COMPRESSION)) {
193+
/*
194+
* The source PAN ID is not compressed out, so
195+
* fetch it. (Otherwise, we'll use the destination
196+
* PAN ID, fetched above.)
197+
*/
198+
if (caplen < 2) {
199+
ND_PRINT((ndo, "[|802.15.4]"));
200+
return hdrlen;
168201
}
169-
ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(ndo, p)));
170-
p += 8;
171-
break;
202+
panid = EXTRACT_LE_16BITS(p);
203+
p += 2;
204+
caplen -= 2;
205+
hdrlen += 2;
172206
}
173-
174-
caplen -= hdrlen;
207+
if (caplen < 8) {
208+
ND_PRINT((ndo, "[|802.15.4]"));
209+
return hdrlen;
210+
}
211+
if (ndo->ndo_vflag)
212+
ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(ndo, p)));
213+
p += 8;
214+
caplen -= 8;
215+
hdrlen += 8;
216+
break;
175217
}
176218

177219
if (!ndo->ndo_suppress_default_print)
178220
ND_DEFAULTPRINT(p, caplen);
179221

180-
return 0;
222+
return hdrlen;
181223
}

Diff for: tests/802_15_4-oobr-1.out

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
IEEE 802.15.4 Beacon packet seq cd [|802.15.4]

Diff for: tests/802_15_4-oobr-1.pcap

79 Bytes
Binary file not shown.

Diff for: tests/802_15_4-oobr-2.out

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
IEEE 802.15.4 Data packet seq 01 [|802.15.4]

Diff for: tests/802_15_4-oobr-2.pcap

78 Bytes
Binary file not shown.

Diff for: tests/TESTLIST

+2
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,8 @@ pimv2-oobr-1 pimv2-oobr-1.pcap pimv2-oobr-1.out -vvv -e
486486
pimv2-oobr-2 pimv2-oobr-2.pcap pimv2-oobr-2.out -vvv -e
487487
pimv2-oobr-3 pimv2-oobr-3.pcap pimv2-oobr-3.out -vvv -e
488488
pimv2-oobr-4 pimv2-oobr-4.pcap pimv2-oobr-4.out -vvv -e
489+
802_15_4-oobr-1 802_15_4-oobr-1.pcap 802_15_4-oobr-1.out -vvv -e
490+
802_15_4-oobr-2 802_15_4-oobr-2.pcap 802_15_4-oobr-2.out -vvv -e
489491

490492
# RTP tests
491493
# fuzzed pcap

0 commit comments

Comments
 (0)