Add additional length checking to IPv6::ToVal

This commit is contained in:
Tim Wojtulewicz 2022-11-15 11:14:40 -07:00
parent ee8e2decec
commit d5a1eb162e
2 changed files with 60 additions and 13 deletions

View file

@ -16,11 +16,22 @@
namespace zeek namespace zeek
{ {
bool IPv6_Hdr::IsOptionTruncated(uint16_t off) const
{
if ( Length() < off )
{
reporter->Weird("truncated_IPv6_option");
return true;
}
return false;
}
static VectorValPtr BuildOptionsVal(const u_char* data, int len) static VectorValPtr BuildOptionsVal(const u_char* data, int len)
{ {
auto vv = make_intrusive<VectorVal>(id::find_type<VectorType>("ip6_options")); auto vv = make_intrusive<VectorVal>(id::find_type<VectorType>("ip6_options"));
while ( static_cast<size_t>(len) >= sizeof(struct ip6_opt) ) while ( len > 0 && static_cast<size_t>(len) >= sizeof(struct ip6_opt) )
{ {
static auto ip6_option_type = id::find_type<RecordType>("ip6_option"); static auto ip6_option_type = id::find_type<RecordType>("ip6_option");
const struct ip6_opt* opt = (const struct ip6_opt*)data; const struct ip6_opt* opt = (const struct ip6_opt*)data;
@ -81,30 +92,40 @@ RecordValPtr IPv6_Hdr::ToVal(VectorValPtr chain) const
case IPPROTO_HOPOPTS: case IPPROTO_HOPOPTS:
{ {
uint16_t off = 2 * sizeof(uint8_t);
if ( IsOptionTruncated(off) )
return nullptr;
static auto ip6_hopopts_type = id::find_type<RecordType>("ip6_hopopts"); static auto ip6_hopopts_type = id::find_type<RecordType>("ip6_hopopts");
rv = make_intrusive<RecordVal>(ip6_hopopts_type); rv = make_intrusive<RecordVal>(ip6_hopopts_type);
const struct ip6_hbh* hbh = (const struct ip6_hbh*)data; const struct ip6_hbh* hbh = (const struct ip6_hbh*)data;
rv->Assign(0, hbh->ip6h_nxt); rv->Assign(0, hbh->ip6h_nxt);
rv->Assign(1, hbh->ip6h_len); rv->Assign(1, hbh->ip6h_len);
uint16_t off = 2 * sizeof(uint8_t);
rv->Assign(2, BuildOptionsVal(data + off, Length() - off)); rv->Assign(2, BuildOptionsVal(data + off, Length() - off));
} }
break; break;
case IPPROTO_DSTOPTS: case IPPROTO_DSTOPTS:
{ {
uint16_t off = 2 * sizeof(uint8_t);
if ( IsOptionTruncated(off) )
return nullptr;
static auto ip6_dstopts_type = id::find_type<RecordType>("ip6_dstopts"); static auto ip6_dstopts_type = id::find_type<RecordType>("ip6_dstopts");
rv = make_intrusive<RecordVal>(ip6_dstopts_type); rv = make_intrusive<RecordVal>(ip6_dstopts_type);
const struct ip6_dest* dst = (const struct ip6_dest*)data; const struct ip6_dest* dst = (const struct ip6_dest*)data;
rv->Assign(0, dst->ip6d_nxt); rv->Assign(0, dst->ip6d_nxt);
rv->Assign(1, dst->ip6d_len); rv->Assign(1, dst->ip6d_len);
uint16_t off = 2 * sizeof(uint8_t);
rv->Assign(2, BuildOptionsVal(data + off, Length() - off)); rv->Assign(2, BuildOptionsVal(data + off, Length() - off));
} }
break; break;
case IPPROTO_ROUTING: case IPPROTO_ROUTING:
{ {
uint16_t off = 4 * sizeof(uint8_t);
if ( IsOptionTruncated(off) )
return nullptr;
static auto ip6_routing_type = id::find_type<RecordType>("ip6_routing"); static auto ip6_routing_type = id::find_type<RecordType>("ip6_routing");
rv = make_intrusive<RecordVal>(ip6_routing_type); rv = make_intrusive<RecordVal>(ip6_routing_type);
const struct ip6_rthdr* rt = (const struct ip6_rthdr*)data; const struct ip6_rthdr* rt = (const struct ip6_rthdr*)data;
@ -112,7 +133,6 @@ RecordValPtr IPv6_Hdr::ToVal(VectorValPtr chain) const
rv->Assign(1, rt->ip6r_len); rv->Assign(1, rt->ip6r_len);
rv->Assign(2, rt->ip6r_type); rv->Assign(2, rt->ip6r_type);
rv->Assign(3, rt->ip6r_segleft); rv->Assign(3, rt->ip6r_segleft);
uint16_t off = 4 * sizeof(uint8_t);
rv->Assign(4, new String(data + off, Length() - off, true)); rv->Assign(4, new String(data + off, Length() - off, true));
} }
break; break;
@ -192,20 +212,26 @@ RecordValPtr IPv6_Hdr::ToVal(VectorValPtr chain) const
{ {
case 0: case 0:
{ {
off += sizeof(uint16_t);
if ( IsOptionTruncated(off) )
break;
auto m = make_intrusive<RecordVal>(ip6_mob_brr_type); auto m = make_intrusive<RecordVal>(ip6_mob_brr_type);
m->Assign(0, ntohs(*((uint16_t*)msg_data))); m->Assign(0, ntohs(*((uint16_t*)msg_data)));
off += sizeof(uint16_t);
m->Assign(1, BuildOptionsVal(data + off, Length() - off)); m->Assign(1, BuildOptionsVal(data + off, Length() - off));
msg->Assign(1, std::move(m)); msg->Assign(1, std::move(m));
}
break; break;
}
case 1: case 1:
{ {
off += sizeof(uint16_t) + sizeof(uint64_t);
if ( IsOptionTruncated(off) )
break;
auto m = make_intrusive<RecordVal>(ip6_mob_hoti_type); auto m = make_intrusive<RecordVal>(ip6_mob_hoti_type);
m->Assign(0, ntohs(*((uint16_t*)msg_data))); m->Assign(0, ntohs(*((uint16_t*)msg_data)));
m->Assign(1, ntohll(*((uint64_t*)(msg_data + sizeof(uint16_t))))); m->Assign(1, ntohll(*((uint64_t*)(msg_data + sizeof(uint16_t)))));
off += sizeof(uint16_t) + sizeof(uint64_t);
m->Assign(2, BuildOptionsVal(data + off, Length() - off)); m->Assign(2, BuildOptionsVal(data + off, Length() - off));
msg->Assign(2, std::move(m)); msg->Assign(2, std::move(m));
break; break;
@ -213,10 +239,13 @@ RecordValPtr IPv6_Hdr::ToVal(VectorValPtr chain) const
case 2: case 2:
{ {
off += sizeof(uint16_t) + sizeof(uint64_t);
if ( IsOptionTruncated(off) )
break;
auto m = make_intrusive<RecordVal>(ip6_mob_coti_type); auto m = make_intrusive<RecordVal>(ip6_mob_coti_type);
m->Assign(0, ntohs(*((uint16_t*)msg_data))); m->Assign(0, ntohs(*((uint16_t*)msg_data)));
m->Assign(1, ntohll(*((uint64_t*)(msg_data + sizeof(uint16_t))))); m->Assign(1, ntohll(*((uint64_t*)(msg_data + sizeof(uint16_t)))));
off += sizeof(uint16_t) + sizeof(uint64_t);
m->Assign(2, BuildOptionsVal(data + off, Length() - off)); m->Assign(2, BuildOptionsVal(data + off, Length() - off));
msg->Assign(3, std::move(m)); msg->Assign(3, std::move(m));
break; break;
@ -224,12 +253,15 @@ RecordValPtr IPv6_Hdr::ToVal(VectorValPtr chain) const
case 3: case 3:
{ {
off += sizeof(uint16_t) + 2 * sizeof(uint64_t);
if ( IsOptionTruncated(off) )
break;
auto m = make_intrusive<RecordVal>(ip6_mob_hot_type); auto m = make_intrusive<RecordVal>(ip6_mob_hot_type);
m->Assign(0, ntohs(*((uint16_t*)msg_data))); m->Assign(0, ntohs(*((uint16_t*)msg_data)));
m->Assign(1, ntohll(*((uint64_t*)(msg_data + sizeof(uint16_t))))); m->Assign(1, ntohll(*((uint64_t*)(msg_data + sizeof(uint16_t)))));
m->Assign( m->Assign(
2, ntohll(*((uint64_t*)(msg_data + sizeof(uint16_t) + sizeof(uint64_t))))); 2, ntohll(*((uint64_t*)(msg_data + sizeof(uint16_t) + sizeof(uint64_t)))));
off += sizeof(uint16_t) + 2 * sizeof(uint64_t);
m->Assign(3, BuildOptionsVal(data + off, Length() - off)); m->Assign(3, BuildOptionsVal(data + off, Length() - off));
msg->Assign(4, std::move(m)); msg->Assign(4, std::move(m));
break; break;
@ -237,12 +269,15 @@ RecordValPtr IPv6_Hdr::ToVal(VectorValPtr chain) const
case 4: case 4:
{ {
off += sizeof(uint16_t) + 2 * sizeof(uint64_t);
if ( IsOptionTruncated(off) )
break;
auto m = make_intrusive<RecordVal>(ip6_mob_cot_type); auto m = make_intrusive<RecordVal>(ip6_mob_cot_type);
m->Assign(0, ntohs(*((uint16_t*)msg_data))); m->Assign(0, ntohs(*((uint16_t*)msg_data)));
m->Assign(1, ntohll(*((uint64_t*)(msg_data + sizeof(uint16_t))))); m->Assign(1, ntohll(*((uint64_t*)(msg_data + sizeof(uint16_t)))));
m->Assign( m->Assign(
2, ntohll(*((uint64_t*)(msg_data + sizeof(uint16_t) + sizeof(uint64_t))))); 2, ntohll(*((uint64_t*)(msg_data + sizeof(uint16_t) + sizeof(uint64_t)))));
off += sizeof(uint16_t) + 2 * sizeof(uint64_t);
m->Assign(3, BuildOptionsVal(data + off, Length() - off)); m->Assign(3, BuildOptionsVal(data + off, Length() - off));
msg->Assign(5, std::move(m)); msg->Assign(5, std::move(m));
break; break;
@ -250,6 +285,10 @@ RecordValPtr IPv6_Hdr::ToVal(VectorValPtr chain) const
case 5: case 5:
{ {
off += 3 * sizeof(uint16_t);
if ( IsOptionTruncated(off) )
break;
auto m = make_intrusive<RecordVal>(ip6_mob_bu_type); auto m = make_intrusive<RecordVal>(ip6_mob_bu_type);
m->Assign(0, ntohs(*((uint16_t*)msg_data))); m->Assign(0, ntohs(*((uint16_t*)msg_data)));
m->Assign(1, static_cast<bool>( m->Assign(1, static_cast<bool>(
@ -261,7 +300,6 @@ RecordValPtr IPv6_Hdr::ToVal(VectorValPtr chain) const
m->Assign(4, static_cast<bool>( m->Assign(4, static_cast<bool>(
ntohs(*((uint16_t*)(msg_data + sizeof(uint16_t)))) & 0x1000)); ntohs(*((uint16_t*)(msg_data + sizeof(uint16_t)))) & 0x1000));
m->Assign(5, ntohs(*((uint16_t*)(msg_data + 2 * sizeof(uint16_t))))); m->Assign(5, ntohs(*((uint16_t*)(msg_data + 2 * sizeof(uint16_t)))));
off += 3 * sizeof(uint16_t);
m->Assign(6, BuildOptionsVal(data + off, Length() - off)); m->Assign(6, BuildOptionsVal(data + off, Length() - off));
msg->Assign(6, std::move(m)); msg->Assign(6, std::move(m));
break; break;
@ -269,13 +307,16 @@ RecordValPtr IPv6_Hdr::ToVal(VectorValPtr chain) const
case 6: case 6:
{ {
off += 3 * sizeof(uint16_t);
if ( IsOptionTruncated(off) )
break;
auto m = make_intrusive<RecordVal>(ip6_mob_back_type); auto m = make_intrusive<RecordVal>(ip6_mob_back_type);
m->Assign(0, *((uint8_t*)msg_data)); m->Assign(0, *((uint8_t*)msg_data));
m->Assign(1, m->Assign(1,
static_cast<bool>(*((uint8_t*)(msg_data + sizeof(uint8_t))) & 0x80)); static_cast<bool>(*((uint8_t*)(msg_data + sizeof(uint8_t))) & 0x80));
m->Assign(2, ntohs(*((uint16_t*)(msg_data + sizeof(uint16_t))))); m->Assign(2, ntohs(*((uint16_t*)(msg_data + sizeof(uint16_t)))));
m->Assign(3, ntohs(*((uint16_t*)(msg_data + 2 * sizeof(uint16_t))))); m->Assign(3, ntohs(*((uint16_t*)(msg_data + 2 * sizeof(uint16_t)))));
off += 3 * sizeof(uint16_t);
m->Assign(4, BuildOptionsVal(data + off, Length() - off)); m->Assign(4, BuildOptionsVal(data + off, Length() - off));
msg->Assign(7, std::move(m)); msg->Assign(7, std::move(m));
break; break;
@ -283,11 +324,14 @@ RecordValPtr IPv6_Hdr::ToVal(VectorValPtr chain) const
case 7: case 7:
{ {
off += sizeof(uint16_t) + sizeof(in6_addr);
if ( IsOptionTruncated(off) )
break;
auto m = make_intrusive<RecordVal>(ip6_mob_be_type); auto m = make_intrusive<RecordVal>(ip6_mob_be_type);
m->Assign(0, *((uint8_t*)msg_data)); m->Assign(0, *((uint8_t*)msg_data));
const in6_addr* hoa = (const in6_addr*)(msg_data + sizeof(uint16_t)); const in6_addr* hoa = (const in6_addr*)(msg_data + sizeof(uint16_t));
m->Assign(1, make_intrusive<AddrVal>(IPAddr(*hoa))); m->Assign(1, make_intrusive<AddrVal>(IPAddr(*hoa)));
off += sizeof(uint16_t) + sizeof(in6_addr);
m->Assign(2, BuildOptionsVal(data + off, Length() - off)); m->Assign(2, BuildOptionsVal(data + off, Length() - off));
msg->Assign(8, std::move(m)); msg->Assign(8, std::move(m));
break; break;

View file

@ -151,6 +151,9 @@ public:
protected: protected:
uint8_t type; uint8_t type;
const u_char* data; const u_char* data;
private:
bool IsOptionTruncated(uint16_t off) const;
}; };
class IPv6_Hdr_Chain class IPv6_Hdr_Chain