defrag/ipv6: support maximum payload length

The maximum IPv6 payload of 65535 bytes results in a packet of 65575
bytes when the fixed header is included. This was truncated to a u16
before decoding a reassembled packet, causing it to bypass further
inspection.

Use a u32 for the IPv6 decoder length so maximum sized reassembled
packets are fully inspected.

Ticket: #8818
pull/16213/head
Jason Ish 3 months ago committed by Victor Julien
parent 1acc170fde
commit a01636c84b

@ -522,7 +522,7 @@ static void DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
}
static const IPV6Hdr *DecodeIPV6Packet(
ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
{
if (unlikely(len < IPV6_HEADER_LEN)) {
ENGINE_SET_INVALID_EVENT(p, IPV6_PKT_TOO_SMALL);
@ -537,7 +537,7 @@ static const IPV6Hdr *DecodeIPV6Packet(
const IPV6Hdr *ip6h = PacketSetIPV6(p, pkt);
if (unlikely(len < (IPV6_HEADER_LEN + IPV6_GET_RAW_PLEN(ip6h)))) {
if (unlikely(len < (uint32_t)(IPV6_HEADER_LEN + IPV6_GET_RAW_PLEN(ip6h)))) {
ENGINE_SET_INVALID_EVENT(p, IPV6_TRUNC_PKT);
return NULL;
}
@ -548,7 +548,7 @@ static const IPV6Hdr *DecodeIPV6Packet(
return ip6h;
}
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
{
StatsCounterIncr(&tv->stats, dtv->counter_ipv6);

@ -82,10 +82,7 @@ int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
event = MPLS_BAD_LABEL_ROUTER_ALERT;
}
else if (label == MPLS_LABEL_IPV6) {
if (len > USHRT_MAX) {
return TM_ECODE_FAILED;
}
return DecodeIPV6(tv, dtv, p, pkt, (uint16_t)len);
return DecodeIPV6(tv, dtv, p, pkt, len);
}
else if (label == MPLS_LABEL_NULL) {
/* Shouldn't appear on the wire. */
@ -115,10 +112,7 @@ int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
DecodeIPV4(tv, dtv, p, pkt, (uint16_t)len);
break;
case MPLS_PROTO_IPV6:
if (len > USHRT_MAX) {
return TM_ECODE_FAILED;
}
DecodeIPV6(tv, dtv, p, pkt, (uint16_t)len);
DecodeIPV6(tv, dtv, p, pkt, len);
break;
case MPLS_PROTO_ETHERNET_PW:
DecodeEthernet(tv, dtv, p, pkt + MPLS_PW_LEN, len - MPLS_PW_LEN);

@ -111,10 +111,7 @@ int DecodeNSH(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *p
}
return DecodeIPV4(tv, dtv, p, pkt + length, (uint16_t)(len - length));
case NSH_NEXT_PROTO_IPV6:
if (len - length > USHRT_MAX) {
return TM_ECODE_FAILED;
}
return DecodeIPV6(tv, dtv, p, pkt + length, (uint16_t)(len - length));
return DecodeIPV6(tv, dtv, p, pkt + length, len - length);
case NSH_NEXT_PROTO_ETHERNET:
return DecodeEthernet(tv, dtv, p, pkt + length, len - length);
case NSH_NEXT_PROTO_MPLS:

@ -60,9 +60,6 @@ int DecodeNull(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
return TM_ECODE_FAILED;
}
if (unlikely(GET_PKT_LEN(p) > HDR_SIZE + USHRT_MAX)) {
return TM_ECODE_FAILED;
}
#if __BYTE_ORDER__ == __BIG_ENDIAN
uint32_t type = pkt[0] | pkt[1] << 8 | pkt[2] << 16 | pkt[3] << 24;
#else
@ -84,11 +81,7 @@ int DecodeNull(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
case AF_INET6_SOLARIS:
case AF_INET6_WINSOCK:
SCLogDebug("IPV6 Packet");
if (GET_PKT_LEN(p) - HDR_SIZE > USHRT_MAX) {
return TM_ECODE_FAILED;
}
DecodeIPV6(
tv, dtv, p, GET_PKT_DATA(p) + HDR_SIZE, (uint16_t)(GET_PKT_LEN(p) - HDR_SIZE));
DecodeIPV6(tv, dtv, p, GET_PKT_DATA(p) + HDR_SIZE, GET_PKT_LEN(p) - HDR_SIZE);
break;
default:
SCLogDebug("Unknown Null packet type version %" PRIu32 "", type);

@ -60,8 +60,7 @@ static int DecodePPPCompressedProto(ThreadVars *tv, DecodeThreadVars *dtv, Packe
return TM_ECODE_FAILED;
}
DEBUG_VALIDATE_BUG_ON(len < data_offset);
uint16_t iplen = (uint16_t)MIN((uint32_t)USHRT_MAX, len - data_offset);
return DecodeIPV6(tv, dtv, p, pkt + data_offset, iplen);
return DecodeIPV6(tv, dtv, p, pkt + data_offset, len - data_offset);
}
case 0x2f: /* PPP_VJ_UCOMP */
if (unlikely(len < (data_offset + IPV4_HEADER_LEN))) {
@ -123,11 +122,7 @@ static int DecodePPPUncompressedProto(ThreadVars *tv, DecodeThreadVars *dtv, Pac
ENGINE_SET_INVALID_EVENT(p, PPPIPV6_PKT_TOO_SMALL);
return TM_ECODE_FAILED;
}
if (unlikely(len > data_offset + USHRT_MAX)) {
return TM_ECODE_FAILED;
}
return DecodeIPV6(tv, dtv, p, pkt + data_offset, (uint16_t)(len - data_offset));
return DecodeIPV6(tv, dtv, p, pkt + data_offset, len - data_offset);
case PPP_IPCP:
case PPP_IPV6CP:

@ -235,11 +235,7 @@ int DecodePPPOESession(
ENGINE_SET_INVALID_EVENT(p, PPPIPV6_PKT_TOO_SMALL);
return TM_ECODE_OK;
}
if (unlikely(len - pppoesh_len > USHRT_MAX)) {
return TM_ECODE_FAILED;
}
DecodeIPV6(tv, dtv, p, pkt + pppoesh_len, (uint16_t)(len - pppoesh_len));
DecodeIPV6(tv, dtv, p, pkt + pppoesh_len, len - pppoesh_len);
break;
default:

@ -61,11 +61,8 @@ int DecodeRaw(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
SCLogDebug("IPV4 Packet");
DecodeIPV4(tv, dtv, p, GET_PKT_DATA(p), (uint16_t)(GET_PKT_LEN(p)));
} else if (IP_GET_RAW_VER(pkt) == 6) {
if (unlikely(GET_PKT_LEN(p) > USHRT_MAX)) {
return TM_ECODE_FAILED;
}
SCLogDebug("IPV6 Packet");
DecodeIPV6(tv, dtv, p, GET_PKT_DATA(p), (uint16_t)(GET_PKT_LEN(p)));
DecodeIPV6(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p));
} else {
SCLogDebug("Unknown ip version %d", IP_GET_RAW_VER(pkt));
ENGINE_SET_EVENT(p,IPRAW_INVALID_IPV);

@ -193,8 +193,7 @@ static int DecodeTunnel(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const
return DecodeIPV4(tv, dtv, p, pkt, (uint16_t)len);
case DECODE_TUNNEL_IPV6:
case DECODE_TUNNEL_IPV6_TEREDO:
DEBUG_VALIDATE_BUG_ON(len > UINT16_MAX);
return DecodeIPV6(tv, dtv, p, pkt, (uint16_t)len);
return DecodeIPV6(tv, dtv, p, pkt, len);
case DECODE_TUNNEL_VLAN:
return DecodeVLAN(tv, dtv, p, pkt, len);
case DECODE_TUNNEL_ETHERNET:

@ -1191,7 +1191,7 @@ int DecodePPPOEDiscovery(ThreadVars *, DecodeThreadVars *, Packet *, const uint8
int DecodeNull(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);
int DecodeRaw(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);
int DecodeIPV4(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint16_t);
int DecodeIPV6(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint16_t);
int DecodeIPV6(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);
int DecodeICMPV4(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);
int DecodeICMPV6(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);
int DecodeTCP(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint16_t);
@ -1503,8 +1503,7 @@ static inline bool DecodeNetworkLayer(ThreadVars *tv, DecodeThreadVars *dtv,
break;
}
case ETHERNET_TYPE_IPV6: {
uint16_t ip_len = (len < USHRT_MAX) ? (uint16_t)len : (uint16_t)USHRT_MAX;
DecodeIPV6(tv, dtv, p, data, ip_len);
DecodeIPV6(tv, dtv, p, data, len);
break;
}
case ETHERNET_TYPE_PPPOE_SESS:

@ -1091,14 +1091,13 @@ Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
if (rp != NULL) {
const uint32_t len = GET_PKT_LEN(rp) - (uint32_t)tracker_ip_hdr_offset;
DEBUG_VALIDATE_BUG_ON(len > UINT16_MAX);
int decode_rc;
if (tracker_af == AF_INET) {
DEBUG_VALIDATE_BUG_ON(len > UINT16_MAX);
decode_rc = DecodeIPV4(
tv, dtv, rp, GET_PKT_DATA(rp) + tracker_ip_hdr_offset, (uint16_t)len);
} else {
decode_rc = DecodeIPV6(
tv, dtv, rp, GET_PKT_DATA(rp) + tracker_ip_hdr_offset, (uint16_t)len);
decode_rc = DecodeIPV6(tv, dtv, rp, GET_PKT_DATA(rp) + tracker_ip_hdr_offset, len);
}
if (decode_rc != TM_ECODE_OK) {
rp->root = NULL;

Loading…
Cancel
Save