diff --git a/src/iosource/Packet.cc b/src/iosource/Packet.cc index d40941095a..9c2c70454c 100644 --- a/src/iosource/Packet.cc +++ b/src/iosource/Packet.cc @@ -47,6 +47,12 @@ void Packet::Init(int arg_link_type, struct timeval *arg_ts, uint32 arg_caplen, l2_valid = false; + if ( data && cap_len < hdr_size ) + { + Weird("truncated_header"); + return; + } + if ( data ) ProcessLayer2(); } @@ -94,12 +100,14 @@ void Packet::ProcessLayer2() bool have_mpls = false; const u_char* pdata = data; + unsigned int remaining = cap_len; switch ( link_type ) { case DLT_NULL: { int protocol = (pdata[3] << 24) + (pdata[2] << 16) + (pdata[1] << 8) + pdata[0]; pdata += GetLinkHeaderSize(link_type); + remaining -= GetLinkHeaderSize(link_type); // From the Wireshark Wiki: "AF_INET6, unfortunately, has // different values in {NetBSD,OpenBSD,BSD/OS}, @@ -127,6 +135,7 @@ void Packet::ProcessLayer2() // Get protocol being carried from the ethernet frame. int protocol = (pdata[12] << 8) + pdata[13]; pdata += GetLinkHeaderSize(link_type); + remaining -= GetLinkHeaderSize(link_type); eth_type = protocol; switch ( protocol ) @@ -140,9 +149,15 @@ void Packet::ProcessLayer2() // 802.1q / 802.1ad case 0x8100: case 0x9100: + if ( remaining < 4 ) + { + Weird("truncated_header"); + return; + } vlan = ((pdata[0] << 8) + pdata[1]) & 0xfff; protocol = ((pdata[2] << 8) + pdata[3]); pdata += 4; // Skip the vlan header + remaining -= 4; // Check for MPLS in VLAN. if ( protocol == 0x8847 ) @@ -154,9 +169,15 @@ void Packet::ProcessLayer2() // Check for double-tagged (802.1ad) if ( protocol == 0x8100 || protocol == 0x9100 ) { + if ( remaining < 4 ) + { + Weird("truncated_header"); + return; + } inner_vlan = ((pdata[0] << 8) + pdata[1]) & 0xfff; protocol = ((pdata[2] << 8) + pdata[3]); pdata += 4; // Skip the vlan header + remaining -= 4; } eth_type = protocol; @@ -166,6 +187,7 @@ void Packet::ProcessLayer2() case 0x8864: protocol = (pdata[6] << 8) + pdata[7]; pdata += 8; // Skip the PPPoE session and PPP header + remaining -= 8; if ( protocol == 0x0021 ) l3_proto = L3_IPV4; @@ -206,6 +228,7 @@ void Packet::ProcessLayer2() // Get PPP protocol. int protocol = (pdata[2] << 8) + pdata[3]; pdata += GetLinkHeaderSize(link_type); + remaining -= GetLinkHeaderSize(link_type); if ( protocol == 0x0281 ) { @@ -230,6 +253,12 @@ void Packet::ProcessLayer2() { // Assume we're pointing at IP. Just figure out which version. pdata += GetLinkHeaderSize(link_type); + if ( remaining < sizeof(struct ip) ) + { + Weird("truncated_header"); + return; + } + const struct ip* ip = (const struct ip *)pdata; if ( ip->ip_v == 4 ) @@ -254,8 +283,14 @@ void Packet::ProcessLayer2() while ( ! end_of_stack ) { + if ( remaining < 4 ) + { + Weird("truncated_header"); + return; + } end_of_stack = *(pdata + 2) & 0x01; pdata += 4; + remaining -= 4; if ( pdata >= pdata + cap_len ) { @@ -288,12 +323,13 @@ void Packet::ProcessLayer2() else if ( encap_hdr_size ) { // Blanket encapsulation. We assume that what remains is IP. - pdata += encap_hdr_size; - if ( pdata + sizeof(struct ip) >= data + cap_len ) + if ( pdata + encap_hdr_size + sizeof(struct ip) >= data + cap_len ) { Weird("no_ip_left_after_encap"); return; } + pdata += encap_hdr_size; + remaining -= encap_hdr_size; const struct ip* ip = (const struct ip *)pdata; diff --git a/testing/btest/Baseline/core.truncation/output b/testing/btest/Baseline/core.truncation/output index 9243c2f873..46d3eecceb 100644 --- a/testing/btest/Baseline/core.truncation/output +++ b/testing/btest/Baseline/core.truncation/output @@ -3,38 +3,48 @@ #empty_field (empty) #unset_field - #path weird -#open 2012-04-11-16-01-35 +#open 2015-08-31-19-57-29 #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p name addl notice peer #types time string addr port addr port string string bool string 1334160095.895421 - - - - - truncated_IP - F bro -#close 2012-04-11-16-01-35 +#close 2015-08-31-19-57-29 #separator \x09 #set_separator , #empty_field (empty) #unset_field - #path weird -#open 2012-04-11-14-57-21 +#open 2015-08-31-19-57-30 #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p name addl notice peer #types time string addr port addr port string string bool string 1334156241.519125 - - - - - truncated_IP - F bro -#close 2012-04-11-14-57-21 +#close 2015-08-31-19-57-30 #separator \x09 #set_separator , #empty_field (empty) #unset_field - #path weird -#open 2012-04-10-21-50-48 +#open 2015-08-31-19-57-31 #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p name addl notice peer #types time string addr port addr port string string bool string 1334094648.590126 - - - - - truncated_IP - F bro -#close 2012-04-10-21-50-48 +#close 2015-08-31-19-57-31 #separator \x09 #set_separator , #empty_field (empty) #unset_field - #path weird -#open 2012-05-29-22-02-34 +#open 2015-08-31-19-57-32 #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p name addl notice peer #types time string addr port addr port string string bool string 1338328954.078361 - - - - - internally_truncated_header - F bro -#close 2012-05-29-22-02-34 +#close 2015-08-31-19-57-32 +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path weird +#open 2015-08-31-19-57-33 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p name addl notice peer +#types time string addr port addr port string string bool string +0.000000 - - - - - truncated_header - F bro +#close 2015-08-31-19-57-33 diff --git a/testing/btest/Traces/trunc/trunc-hdr.pcap b/testing/btest/Traces/trunc/trunc-hdr.pcap new file mode 100644 index 0000000000..0ab12ee6c7 Binary files /dev/null and b/testing/btest/Traces/trunc/trunc-hdr.pcap differ diff --git a/testing/btest/core/truncation.test b/testing/btest/core/truncation.test index 3406879183..c0e4ee857a 100644 --- a/testing/btest/core/truncation.test +++ b/testing/btest/core/truncation.test @@ -19,4 +19,10 @@ # @TEST-EXEC: bro -r $TRACES/trunc/icmp-header-trunc.pcap # @TEST-EXEC: cat weird.log >> output + +# Truncated packets where the captured length is less than the length required +# for the packet header should also raise a Weird +# @TEST-EXEC: bro -r $TRACES/trunc/trunc-hdr.pcap +# @TEST-EXEC: cat weird.log >> output + # @TEST-EXEC: btest-diff output