From owner-svn-src-all@freebsd.org Wed Jan 24 19:48:25 2018 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id C9807EC1C86; Wed, 24 Jan 2018 19:48:25 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 7F04474173; Wed, 24 Jan 2018 19:48:25 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 75F722211C; Wed, 24 Jan 2018 19:48:25 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w0OJmPii022488; Wed, 24 Jan 2018 19:48:25 GMT (envelope-from ae@FreeBSD.org) Received: (from ae@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w0OJmPus022487; Wed, 24 Jan 2018 19:48:25 GMT (envelope-from ae@FreeBSD.org) Message-Id: <201801241948.w0OJmPus022487@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ae set sender to ae@FreeBSD.org using -f From: "Andrey V. Elsukov" Date: Wed, 24 Jan 2018 19:48:25 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r328352 - head/sys/netipsec X-SVN-Group: head X-SVN-Commit-Author: ae X-SVN-Commit-Paths: head/sys/netipsec X-SVN-Commit-Revision: 328352 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.25 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jan 2018 19:48:26 -0000 Author: ae Date: Wed Jan 24 19:48:25 2018 New Revision: 328352 URL: https://svnweb.freebsd.org/changeset/base/328352 Log: Adopt revision 1.76 and 1.77 from NetBSD: Fix a vulnerability in IPsec-IPv6-AH, that allows an attacker to remotely crash the kernel with a single packet. In this loop we need to increment 'ad' by two, because the length field of the option header does not count the size of the option header itself. If the length is zero, then 'count' is incremented by zero, and there's an infinite loop. Beyond that, this code was written with the assumption that since the IPv6 packet already went through the generic IPv6 option parser, several fields are guaranteed to be valid; but this assumption does not hold because of the missing '+2', and there's as a result a triggerable buffer overflow (write zeros after the end of the mbuf, potentially to the next mbuf in memory since it's a pool). Add the missing '+2', this place will be reinforced in separate commits. Reported by: Maxime Villard MFC after: 1 week Modified: head/sys/netipsec/xform_ah.c Modified: head/sys/netipsec/xform_ah.c ============================================================================== --- head/sys/netipsec/xform_ah.c Wed Jan 24 19:37:18 2018 (r328351) +++ head/sys/netipsec/xform_ah.c Wed Jan 24 19:48:25 2018 (r328352) @@ -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) { @@ -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);