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
struct ip6_ext *ip6e;
struct ip6_hdr ip6;
int alloc, len, ad;
int ad, alloc, nxt, noff;
#endif /* INET6 */
switch (proto) {
@ -330,7 +330,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out)
else
ip->ip_off = htons(0);
ptr = mtod(m, unsigned char *) + sizeof(struct ip);
ptr = mtod(m, unsigned char *);
/* IPv4 option processing */
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. */
count = ptr[off + 1];
bcopy(ipseczeroes, ptr, count);
bcopy(ipseczeroes, ptr + off, count);
off += count;
break;
}
@ -484,61 +484,45 @@ ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out)
} else
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);)
switch (off) {
for (off = 0; off < skip - sizeof(struct ip6_hdr);)
switch (nxt) {
case IPPROTO_HOPOPTS:
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
* options -- borrows heavily from the
* KAME code.
* Zero out mutable options.
*/
for (count = len + sizeof(struct ip6_ext);
count < len + ((ip6e->ip6e_len + 1) << 3);) {
for (count = off + sizeof(struct ip6_ext);
count < noff;) {
if (ptr[count] == IP6OPT_PAD1) {
count++;
continue; /* Skip padding. */
}
/* Sanity check. */
if (count > len +
((ip6e->ip6e_len + 1) << 3)) {
m_freem(m);
ad = ptr[count + 1] + 2;
if (count + ad > noff)
goto error6;
/* 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)
bcopy(ipseczeroes, ptr + count,
ptr[count + 1]);
memset(ptr + count, 0, 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. */
len += ((ip6e->ip6e_len + 1) << 3);
off = ip6e->ip6e_nxt;
off += ((ip6e->ip6e_len + 1) << 3);
nxt = ip6e->ip6e_nxt;
break;
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
* computation.
*/
ip6e = (struct ip6_ext *) (ptr + len);
len += ((ip6e->ip6e_len + 1) << 3);
off = ip6e->ip6e_nxt;
ip6e = (struct ip6_ext *) (ptr + off);
off += ((ip6e->ip6e_len + 1) << 3);
nxt = ip6e->ip6e_nxt;
break;
default:
DPRINTF(("%s: unexpected IPv6 header type %d",
__func__, off));
error6:
if (alloc)
free(ptr, M_XDATA);
m_freem(m);