aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGordon Tetlow <gordon@FreeBSD.org>2018-04-04 05:37:52 +0000
committerGordon Tetlow <gordon@FreeBSD.org>2018-04-04 05:37:52 +0000
commit9da63612b3aeb907f8a4ea728a9a082b28799192 (patch)
tree2d7654b0e5ce97f0533cdd2cf9e416685b260749
parenta500153f5edf1c468350f1f60ca54f0c3a9dda7b (diff)
downloadsrc-9da63612b3aeb907f8a4ea728a9a082b28799192.tar.gz
src-9da63612b3aeb907f8a4ea728a9a082b28799192.zip
Fix ipsec crash or denial of service. [SA-18:05.ipsec]
Reported by: Maxime Villard Approved by: so Security: CVE-2018-6918 Security: FreeBSD-SA-18:05.ipsec
Notes
Notes: svn path=/releng/10.3/; revision=331985
-rw-r--r--sys/netipsec/xform_ah.c72
1 files changed, 28 insertions, 44 deletions
diff --git a/sys/netipsec/xform_ah.c b/sys/netipsec/xform_ah.c
index 5593768842c9..48dd61b6eb67 100644
--- a/sys/netipsec/xform_ah.c
+++ b/sys/netipsec/xform_ah.c
@@ -285,7 +285,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) {
@@ -314,7 +314,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;) {
@@ -395,7 +395,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;
}
@@ -468,61 +468,44 @@ 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);
-
- /* Free, if we allocated. */
- if (alloc)
- free(ptr, M_XDATA);
- return EINVAL;
- }
+ ad = ptr[count + 1] + 2;
+ if (count + ad > noff)
+ goto error6;
- 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:
@@ -530,14 +513,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);