Fix denial of service of ipsec.

Corresponding upstream changeset from
 https://www.freebsd.org/security/advisories/FreeBSD-SA-18:05.ipsec.asc.
dev
fengbojiang(姜凤波) 2019-11-22 12:33:19 +08:00
parent 04b1440d33
commit d0b1b30af0
1 changed files with 28 additions and 43 deletions

View File

@ -301,7 +301,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out)
#ifdef INET6 #ifdef INET6
struct ip6_ext *ip6e; struct ip6_ext *ip6e;
struct ip6_hdr ip6; struct ip6_hdr ip6;
int alloc, len, ad; int ad, alloc, nxt, noff;
#endif /* INET6 */ #endif /* INET6 */
switch (proto) { switch (proto) {
@ -330,7 +330,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out)
else else
ip->ip_off = htons(0); ip->ip_off = htons(0);
ptr = mtod(m, unsigned char *) + sizeof(struct ip); ptr = mtod(m, unsigned char *);
/* IPv4 option processing */ /* IPv4 option processing */
for (off = sizeof(struct ip); off < skip;) { for (off = sizeof(struct ip); off < skip;) {
@ -411,7 +411,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out)
/* Zeroize all other options. */ /* Zeroize all other options. */
count = ptr[off + 1]; count = ptr[off + 1];
bcopy(ipseczeroes, ptr, count); bcopy(ipseczeroes, ptr + off, count);
off += count; off += count;
break; break;
} }
@ -484,61 +484,45 @@ ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out)
} else } else
break; break;
off = ip6.ip6_nxt & 0xff; /* Next header type. */ nxt = ip6.ip6_nxt & 0xff; /* Next header type. */
for (len = 0; len < skip - sizeof(struct ip6_hdr);) for (off = 0; off < skip - sizeof(struct ip6_hdr);)
switch (off) { switch (nxt) {
case IPPROTO_HOPOPTS: case IPPROTO_HOPOPTS:
case IPPROTO_DSTOPTS: case IPPROTO_DSTOPTS:
ip6e = (struct ip6_ext *) (ptr + len); ip6e = (struct ip6_ext *)(ptr + off);
noff = off + ((ip6e->ip6e_len + 1) << 3);
/* Sanity check. */
if (noff > skip - sizeof(struct ip6_hdr))
goto error6;
/* /*
* Process the mutable/immutable * Zero out mutable options.
* options -- borrows heavily from the
* KAME code.
*/ */
for (count = len + sizeof(struct ip6_ext); for (count = off + sizeof(struct ip6_ext);
count < len + ((ip6e->ip6e_len + 1) << 3);) { count < noff;) {
if (ptr[count] == IP6OPT_PAD1) { if (ptr[count] == IP6OPT_PAD1) {
count++; count++;
continue; /* Skip padding. */ continue; /* Skip padding. */
} }
/* Sanity check. */ ad = ptr[count + 1] + 2;
if (count > len + if (count + ad > noff)
((ip6e->ip6e_len + 1) << 3)) { goto error6;
m_freem(m);
/* Free, if we allocated. */
if (alloc)
free(ptr, M_XDATA);
return EINVAL;
}
ad = ptr[count + 1];
/* If mutable option, zeroize. */
if (ptr[count] & IP6OPT_MUTABLE) if (ptr[count] & IP6OPT_MUTABLE)
bcopy(ipseczeroes, ptr + count, memset(ptr + count, 0, ad);
ptr[count + 1]);
count += ad; count += ad;
/* Sanity check. */
if (count >
skip - sizeof(struct ip6_hdr)) {
m_freem(m);
/* Free, if we allocated. */
if (alloc)
free(ptr, M_XDATA);
return EINVAL;
}
} }
if (count != noff)
goto error6;
/* Advance. */ /* Advance. */
len += ((ip6e->ip6e_len + 1) << 3); off += ((ip6e->ip6e_len + 1) << 3);
off = ip6e->ip6e_nxt; nxt = ip6e->ip6e_nxt;
break; break;
case IPPROTO_ROUTING: case IPPROTO_ROUTING:
@ -546,14 +530,15 @@ ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out)
* Always include routing headers in * Always include routing headers in
* computation. * computation.
*/ */
ip6e = (struct ip6_ext *) (ptr + len); ip6e = (struct ip6_ext *) (ptr + off);
len += ((ip6e->ip6e_len + 1) << 3); off += ((ip6e->ip6e_len + 1) << 3);
off = ip6e->ip6e_nxt; nxt = ip6e->ip6e_nxt;
break; break;
default: default:
DPRINTF(("%s: unexpected IPv6 header type %d", DPRINTF(("%s: unexpected IPv6 header type %d",
__func__, off)); __func__, off));
error6:
if (alloc) if (alloc)
free(ptr, M_XDATA); free(ptr, M_XDATA);
m_freem(m); m_freem(m);