Author: gordon
Date: Wed Apr  4 05:37:52 2018
New Revision: 331985
URL: https://svnweb.freebsd.org/changeset/base/331985

Log:
  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

Modified:
  releng/10.3/sys/netipsec/xform_ah.c
  releng/10.4/sys/netipsec/xform_ah.c
  releng/11.1/sys/netipsec/xform_ah.c

Modified: releng/10.3/sys/netipsec/xform_ah.c
==============================================================================
--- releng/10.3/sys/netipsec/xform_ah.c Wed Apr  4 05:33:56 2018        
(r331984)
+++ releng/10.3/sys/netipsec/xform_ah.c Wed Apr  4 05:37:52 2018        
(r331985)
@@ -285,7 +285,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
 #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 sk
                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 sk
 
                                /* 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 sk
                } 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:
@@ -530,14 +513,15 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
                                 * 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);

Modified: releng/10.4/sys/netipsec/xform_ah.c
==============================================================================
--- releng/10.4/sys/netipsec/xform_ah.c Wed Apr  4 05:33:56 2018        
(r331984)
+++ releng/10.4/sys/netipsec/xform_ah.c Wed Apr  4 05:37:52 2018        
(r331985)
@@ -285,7 +285,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
 #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 sk
                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 sk
 
                                /* 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 sk
                } 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:
@@ -530,14 +513,15 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
                                 * 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);

Modified: releng/11.1/sys/netipsec/xform_ah.c
==============================================================================
--- releng/11.1/sys/netipsec/xform_ah.c Wed Apr  4 05:33:56 2018        
(r331984)
+++ releng/11.1/sys/netipsec/xform_ah.c Wed Apr  4 05:37:52 2018        
(r331985)
@@ -264,7 +264,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
 #ifdef INET6
        struct ip6_ext *ip6e;
        struct ip6_hdr ip6;
-       int alloc, len, ad;
+       int ad, alloc, nxt, noff;
 #endif /* INET6 */
 
        switch (proto) {
@@ -293,7 +293,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
                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;) {
@@ -374,7 +374,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
 
                                /* Zeroize all other options. */
                                count = ptr[off + 1];
-                               bcopy(ipseczeroes, ptr, count);
+                               bcopy(ipseczeroes, ptr + off, count);
                                off += count;
                                break;
                        }
@@ -447,61 +447,44 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
                } 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:
@@ -509,14 +492,15 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
                                 * 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);
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to