Skip to content

Commit ae83295

Browse files
guyharrisinfrastation
authored andcommitted
CVE-2017-13033/VTP: Add more bound and length checks.
This fixes a buffer over-read discovered by Bhargava Shastry. Add a test using the capture file supplied by the reporter(s), modified so the capture file won't be rejected as an invalid capture. Update another VTP test's .out file for this change. Don't treate a TLV type or length of 0 as invalid; a type of 0 should just be reported as illegal if that type isn't used, and the length is the length of the *value*, not the length of the entire TLV, so if it's zero there won't be an infinite loop. (It's still not *legal*, as the values of all the TLVs we handle are 1 16-bit word long; we added a check for that.) Update some comments while we're at it, to give a new URL for one Cisco page and a non-Cisco URL for another former Cisco page (Cisco's UniverCD pages don't seem to be available any more, and Cisco's robots.txt file didn't allow the Wayback Machine to archive it).
1 parent e0d8ee5 commit ae83295

File tree

5 files changed

+84
-64
lines changed

5 files changed

+84
-64
lines changed

Diff for: print-vtp.c

+80-62
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,8 @@
1313
* FOR A PARTICULAR PURPOSE.
1414
*
1515
* Reference documentation:
16-
* http://www.cisco.com/en/US/tech/tk389/tk689/technologies_tech_note09186a0080094c52.shtml
17-
* http://www.cisco.com/warp/public/473/21.html
18-
* http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm
16+
* http://www.cisco.com/c/en/us/support/docs/lan-switching/vtp/10558-21.html
17+
* http://docstore.mik.ua/univercd/cc/td/doc/product/lan/trsrb/frames.htm
1918
*
2019
* Original code ode by Carles Kishimoto <carles.kishimoto@gmail.com>
2120
*/
@@ -36,7 +35,7 @@
3635
#define VTP_DOMAIN_NAME_LEN 32
3736
#define VTP_MD5_DIGEST_LEN 16
3837
#define VTP_UPDATE_TIMESTAMP_LEN 12
39-
#define VTP_VLAN_INFO_OFFSET 12
38+
#define VTP_VLAN_INFO_FIXED_PART_LEN 12 /* length of VLAN info before VLAN name */
4039

4140
#define VTP_SUMMARY_ADV 0x01
4241
#define VTP_SUBSET_ADV 0x02
@@ -252,89 +251,108 @@ vtp_print (netdissect_options *ndo,
252251
ND_TCHECK2(*tptr, len);
253252

254253
vtp_vlan = (const struct vtp_vlan_*)tptr;
254+
if (len < VTP_VLAN_INFO_FIXED_PART_LEN)
255+
goto trunc;
255256
ND_TCHECK(*vtp_vlan);
256257
ND_PRINT((ndo, "\n\tVLAN info status %s, type %s, VLAN-id %u, MTU %u, SAID 0x%08x, Name ",
257258
tok2str(vtp_vlan_status,"Unknown",vtp_vlan->status),
258259
tok2str(vtp_vlan_type_values,"Unknown",vtp_vlan->type),
259260
EXTRACT_16BITS(&vtp_vlan->vlanid),
260261
EXTRACT_16BITS(&vtp_vlan->mtu),
261262
EXTRACT_32BITS(&vtp_vlan->index)));
262-
fn_printzp(ndo, tptr + VTP_VLAN_INFO_OFFSET, vtp_vlan->name_len, NULL);
263-
264-
/*
265-
* Vlan names are aligned to 32-bit boundaries.
266-
*/
267-
len -= VTP_VLAN_INFO_OFFSET + 4*((vtp_vlan->name_len + 3)/4);
268-
tptr += VTP_VLAN_INFO_OFFSET + 4*((vtp_vlan->name_len + 3)/4);
263+
len -= VTP_VLAN_INFO_FIXED_PART_LEN;
264+
tptr += VTP_VLAN_INFO_FIXED_PART_LEN;
265+
if (len < 4*((vtp_vlan->name_len + 3)/4))
266+
goto trunc;
267+
ND_TCHECK2(*tptr, vtp_vlan->name_len);
268+
fn_printzp(ndo, tptr, vtp_vlan->name_len, NULL);
269+
270+
/*
271+
* Vlan names are aligned to 32-bit boundaries.
272+
*/
273+
len -= 4*((vtp_vlan->name_len + 3)/4);
274+
tptr += 4*((vtp_vlan->name_len + 3)/4);
269275

270276
/* TLV information follows */
271277

272278
while (len > 0) {
273279

274280
/*
275-
* Cisco specs says 2 bytes for type + 2 bytes for length, take only 1
276-
* See: http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm
281+
* Cisco specs say 2 bytes for type + 2 bytes for length;
282+
* see http://docstore.mik.ua/univercd/cc/td/doc/product/lan/trsrb/frames.htm
283+
* However, actual packets on the wire appear to use 1
284+
* byte for the type and 1 byte for the length, so that's
285+
* what we do.
277286
*/
287+
if (len < 2)
288+
goto trunc;
289+
ND_TCHECK2(*tptr, 2);
278290
type = *tptr;
279291
tlv_len = *(tptr+1);
280292

281293
ND_PRINT((ndo, "\n\t\t%s (0x%04x) TLV",
282294
tok2str(vtp_vlan_tlv_values, "Unknown", type),
283295
type));
284296

285-
/*
286-
* infinite loop check
287-
*/
288-
if (type == 0 || tlv_len == 0) {
297+
if (len < tlv_len * 2 + 2) {
298+
ND_PRINT((ndo, " (TLV goes past the end of the packet)"));
289299
return;
290300
}
291-
292301
ND_TCHECK2(*tptr, tlv_len * 2 +2);
293302

294-
tlv_value = EXTRACT_16BITS(tptr+2);
295-
296-
switch (type) {
297-
case VTP_VLAN_STE_HOP_COUNT:
298-
ND_PRINT((ndo, ", %u", tlv_value));
299-
break;
300-
301-
case VTP_VLAN_PRUNING:
302-
ND_PRINT((ndo, ", %s (%u)",
303-
tlv_value == 1 ? "Enabled" : "Disabled",
304-
tlv_value));
305-
break;
306-
307-
case VTP_VLAN_STP_TYPE:
308-
ND_PRINT((ndo, ", %s (%u)",
309-
tok2str(vtp_stp_type_values, "Unknown", tlv_value),
310-
tlv_value));
311-
break;
312-
313-
case VTP_VLAN_BRIDGE_TYPE:
314-
ND_PRINT((ndo, ", %s (%u)",
315-
tlv_value == 1 ? "SRB" : "SRT",
316-
tlv_value));
317-
break;
318-
319-
case VTP_VLAN_BACKUP_CRF_MODE:
320-
ND_PRINT((ndo, ", %s (%u)",
321-
tlv_value == 1 ? "Backup" : "Not backup",
322-
tlv_value));
323-
break;
324-
325-
/*
326-
* FIXME those are the defined TLVs that lack a decoder
327-
* you are welcome to contribute code ;-)
328-
*/
329-
330-
case VTP_VLAN_SOURCE_ROUTING_RING_NUMBER:
331-
case VTP_VLAN_SOURCE_ROUTING_BRIDGE_NUMBER:
332-
case VTP_VLAN_PARENT_VLAN:
333-
case VTP_VLAN_TRANS_BRIDGED_VLAN:
334-
case VTP_VLAN_ARP_HOP_COUNT:
335-
default:
336-
print_unknown_data(ndo, tptr, "\n\t\t ", 2 + tlv_len*2);
337-
break;
303+
/*
304+
* We assume the value is a 2-byte integer; the length is
305+
* in units of 16-bit words.
306+
*/
307+
if (tlv_len != 1) {
308+
ND_PRINT((ndo, " (invalid TLV length %u != 1)", tlv_len));
309+
return;
310+
} else {
311+
tlv_value = EXTRACT_16BITS(tptr+2);
312+
313+
switch (type) {
314+
case VTP_VLAN_STE_HOP_COUNT:
315+
ND_PRINT((ndo, ", %u", tlv_value));
316+
break;
317+
318+
case VTP_VLAN_PRUNING:
319+
ND_PRINT((ndo, ", %s (%u)",
320+
tlv_value == 1 ? "Enabled" : "Disabled",
321+
tlv_value));
322+
break;
323+
324+
case VTP_VLAN_STP_TYPE:
325+
ND_PRINT((ndo, ", %s (%u)",
326+
tok2str(vtp_stp_type_values, "Unknown", tlv_value),
327+
tlv_value));
328+
break;
329+
330+
case VTP_VLAN_BRIDGE_TYPE:
331+
ND_PRINT((ndo, ", %s (%u)",
332+
tlv_value == 1 ? "SRB" : "SRT",
333+
tlv_value));
334+
break;
335+
336+
case VTP_VLAN_BACKUP_CRF_MODE:
337+
ND_PRINT((ndo, ", %s (%u)",
338+
tlv_value == 1 ? "Backup" : "Not backup",
339+
tlv_value));
340+
break;
341+
342+
/*
343+
* FIXME those are the defined TLVs that lack a decoder
344+
* you are welcome to contribute code ;-)
345+
*/
346+
347+
case VTP_VLAN_SOURCE_ROUTING_RING_NUMBER:
348+
case VTP_VLAN_SOURCE_ROUTING_BRIDGE_NUMBER:
349+
case VTP_VLAN_PARENT_VLAN:
350+
case VTP_VLAN_TRANS_BRIDGED_VLAN:
351+
case VTP_VLAN_ARP_HOP_COUNT:
352+
default:
353+
print_unknown_data(ndo, tptr, "\n\t\t ", 2 + tlv_len*2);
354+
break;
355+
}
338356
}
339357
len -= 2 + tlv_len*2;
340358
tptr += 2 + tlv_len*2;

Diff for: tests/TESTLIST

+1
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,7 @@ pgm_opts_asan_2 pgm_opts_asan_2.pcap pgm_opts_asan_2.out -v
524524
pgm_opts_asan_3 pgm_opts_asan_3.pcap pgm_opts_asan_3.out -v
525525
vtp_asan vtp_asan.pcap vtp_asan.out -v
526526
vtp_asan-2 vtp_asan-2.pcap vtp_asan-2.out -v
527+
vtp_asan-3 vtp_asan-3.pcap vtp_asan-3.out -v
527528
icmp6_mobileprefix_asan icmp6_mobileprefix_asan.pcap icmp6_mobileprefix_asan.out -v
528529
ip_printroute_asan ip_printroute_asan.pcap ip_printroute_asan.out -v
529530
mobility_opt_asan mobility_opt_asan.pcap mobility_opt_asan.out -v

Diff for: tests/vtp_asan-2.out

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
FRF.16 Frag, seq 193, Flags [Begin, End], UI 08! VTPv69, Message Subset advertisement (0x02), length 2126400013
2-
Domain name: , Seq number: 0, Config Rev fb499603
3-
VLAN info status Unknown, type TrCRF, VLAN-id 256, MTU 771, SAID 0x03030303, Name ^C^I^C[|vtp]
2+
Domain name: , Seq number: 0, Config Rev fb499603[|vtp]

Diff for: tests/vtp_asan-3.out

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
FRF.16 Frag, seq 193, Flags [Begin, End], UI 08! VTPv69, Message Subset advertisement (0x02), length 2126400013
2+
Domain name: , Seq number: 0, Config Rev 4040404[|vtp]

Diff for: tests/vtp_asan-3.pcap

185 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)