Fix malformed ipv6 packet causing an endless loop in exthdr decoding.

remotes/origin/master-1.0.x
Victor Julien 16 years ago
parent 2910759943
commit 54c2804ce4

@ -38,9 +38,11 @@
static void static void
DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq)
{ {
SCEnter();
uint8_t *orig_pkt = pkt; uint8_t *orig_pkt = pkt;
uint8_t nh; uint8_t nh;
uint8_t hdrextlen; uint16_t hdrextlen;
uint16_t plen; uint16_t plen;
char dstopts = 0; char dstopts = 0;
char exthdr_fh_done = 0; char exthdr_fh_done = 0;
@ -50,31 +52,36 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt
while(1) while(1)
{ {
if (plen < 2) /* minimal needed in a hdr */ if (plen < 2) { /* minimal needed in a hdr */
return; SCReturn;
}
switch(nh) switch(nh)
{ {
case IPPROTO_TCP: case IPPROTO_TCP:
IPV6_SET_L4PROTO(p,nh); IPV6_SET_L4PROTO(p,nh);
DecodeTCP(tv, dtv, p, pkt, plen, pq); DecodeTCP(tv, dtv, p, pkt, plen, pq);
return; SCReturn;
case IPPROTO_UDP: case IPPROTO_UDP:
IPV6_SET_L4PROTO(p,nh); IPV6_SET_L4PROTO(p,nh);
DecodeUDP(tv, dtv, p, pkt, plen, pq); DecodeUDP(tv, dtv, p, pkt, plen, pq);
return; SCReturn;
case IPPROTO_ICMPV6: case IPPROTO_ICMPV6:
IPV6_SET_L4PROTO(p,nh); IPV6_SET_L4PROTO(p,nh);
DecodeICMPV6(tv, dtv, p, pkt, plen, pq); DecodeICMPV6(tv, dtv, p, pkt, plen, pq);
return; SCReturn;
case IPPROTO_ROUTING: case IPPROTO_ROUTING:
hdrextlen = (*(pkt+1) + 1) << 3; /* 8 octet units */ hdrextlen = sizeof(IPV6RouteHdr);
hdrextlen += (*(pkt+1) * 8); /* 8 octet units */
SCLogDebug("hdrextlen %"PRIu8, hdrextlen);
if (hdrextlen > plen) { if (hdrextlen > plen) {
DECODER_SET_EVENT(p, IPV6_TRUNC_EXTHDR); DECODER_SET_EVENT(p, IPV6_TRUNC_EXTHDR);
return; SCReturn;
} }
if (p->IPV6_EH_CNT < IPV6_MAX_OPT) if (p->IPV6_EH_CNT < IPV6_MAX_OPT)
@ -98,7 +105,7 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt
IPV6_EXTHDR_SET_RH(p, pkt); IPV6_EXTHDR_SET_RH(p, pkt);
IPV6_EXTHDR_RH(p)->ip6rh_len = hdrextlen; IPV6_EXTHDR_RH(p)->ip6rh_len = hdrextlen;
/** \todo move into own function and load on demand */ /** \todo move into own function and load on demand */
if (IPV6_EXTHDR_RH(p)->ip6rh_type == 0) { if (IPV6_EXTHDR_RH(p)->ip6rh_type == 0) {
uint8_t i; uint8_t i;
@ -109,7 +116,7 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt
* sized */ * sized */
for (i = 0; i < (n/8) && i < sizeof(IPV6_EXTHDR_RH(p)->ip6rh0_addr)/sizeof(struct in6_addr); ++i) { for (i = 0; i < (n/8) && i < sizeof(IPV6_EXTHDR_RH(p)->ip6rh0_addr)/sizeof(struct in6_addr); ++i) {
/* the address header fields are 16 bytes in size */ /* the address header fields are 16 bytes in size */
/** \todo do this without memcpy since it's expensive */ /** \todo do this without memcpy since it's expensive */
memcpy(&IPV6_EXTHDR_RH(p)->ip6rh0_addr[i], pkt+(i*16)+8, sizeof(IPV6_EXTHDR_RH(p)->ip6rh0_addr[i])); memcpy(&IPV6_EXTHDR_RH(p)->ip6rh0_addr[i], pkt+(i*16)+8, sizeof(IPV6_EXTHDR_RH(p)->ip6rh0_addr[i]));
} }
IPV6_EXTHDR_RH(p)->ip6rh0_num_addrs = i; IPV6_EXTHDR_RH(p)->ip6rh0_num_addrs = i;
@ -131,7 +138,7 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt
hdrextlen = (*(pkt+1) + 1) << 3; hdrextlen = (*(pkt+1) + 1) << 3;
if (hdrextlen > plen) { if (hdrextlen > plen) {
DECODER_SET_EVENT(p, IPV6_TRUNC_EXTHDR); DECODER_SET_EVENT(p, IPV6_TRUNC_EXTHDR);
return; SCReturn;
} }
if (p->IPV6_EH_CNT < IPV6_MAX_OPT) if (p->IPV6_EH_CNT < IPV6_MAX_OPT)
@ -264,7 +271,7 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt
hdrextlen = sizeof(IPV6FragHdr); hdrextlen = sizeof(IPV6FragHdr);
if (hdrextlen > plen) { if (hdrextlen > plen) {
DECODER_SET_EVENT(p, IPV6_TRUNC_EXTHDR); DECODER_SET_EVENT(p, IPV6_TRUNC_EXTHDR);
return; SCReturn;
} }
if(p->IPV6_EH_CNT<IPV6_MAX_OPT) if(p->IPV6_EH_CNT<IPV6_MAX_OPT)
@ -297,7 +304,7 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt
hdrextlen = sizeof(IPV6EspHdr); hdrextlen = sizeof(IPV6EspHdr);
if (hdrextlen > plen) { if (hdrextlen > plen) {
DECODER_SET_EVENT(p, IPV6_TRUNC_EXTHDR); DECODER_SET_EVENT(p, IPV6_TRUNC_EXTHDR);
return; SCReturn;
} }
if(p->IPV6_EH_CNT<IPV6_MAX_OPT) if(p->IPV6_EH_CNT<IPV6_MAX_OPT)
@ -311,7 +318,7 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt
if (IPV6_EXTHDR_ISSET_EH(p)) { if (IPV6_EXTHDR_ISSET_EH(p)) {
DECODER_SET_EVENT(p, IPV6_EXTHDR_DUPL_EH); DECODER_SET_EVENT(p, IPV6_EXTHDR_DUPL_EH);
return; SCReturn;
} }
IPV6_EXTHDR_SET_EH(p, pkt); IPV6_EXTHDR_SET_EH(p, pkt);
@ -323,10 +330,16 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt
} }
case IPPROTO_AH: case IPPROTO_AH:
{ {
hdrextlen = (*(pkt+1) + 1) << 3; /* we need the header as a minimum */
hdrextlen = sizeof(IPV6AuthHdr);
/* the payload len field is the number of extra 4 byte fields */
hdrextlen += (*(pkt+1)) * 4;
SCLogDebug("hdrextlen %"PRIu8, hdrextlen);
if (hdrextlen > plen) { if (hdrextlen > plen) {
DECODER_SET_EVENT(p, IPV6_TRUNC_EXTHDR); DECODER_SET_EVENT(p, IPV6_TRUNC_EXTHDR);
return; SCReturn;
} }
if(p->IPV6_EH_CNT<IPV6_MAX_OPT) if(p->IPV6_EH_CNT<IPV6_MAX_OPT)
@ -355,15 +368,15 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt
} }
case IPPROTO_NONE: case IPPROTO_NONE:
IPV6_SET_L4PROTO(p,nh); IPV6_SET_L4PROTO(p,nh);
return; SCReturn;
default: default:
IPV6_SET_L4PROTO(p,nh); IPV6_SET_L4PROTO(p,nh);
return; SCReturn;
} }
} }
return; SCReturn;
} }
static int DecodeIPV6Packet (ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len) static int DecodeIPV6Packet (ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len)

Loading…
Cancel
Save