From owner-svn-src-head@FreeBSD.ORG Thu Jun 18 18:28:39 2015 Return-Path: Delivered-To: svn-src-head@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 086F29FC; Thu, 18 Jun 2015 18:28:39 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id EAA28612; Thu, 18 Jun 2015 18:28:38 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t5IISc05060635; Thu, 18 Jun 2015 18:28:38 GMT (envelope-from ae@FreeBSD.org) Received: (from ae@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t5IIScG0060634; Thu, 18 Jun 2015 18:28:38 GMT (envelope-from ae@FreeBSD.org) Message-Id: <201506181828.t5IIScG0060634@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: ae set sender to ae@FreeBSD.org using -f From: "Andrey V. Elsukov" Date: Thu, 18 Jun 2015 18:28:38 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r284566 - head/sys/netinet X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Jun 2015 18:28:39 -0000 Author: ae Date: Thu Jun 18 18:28:38 2015 New Revision: 284566 URL: https://svnweb.freebsd.org/changeset/base/284566 Log: Fix possible use after free in encap[46]_input(). There is small window, when encap_detach() can free matched entry directly after we release encapmtx. Instead of use pointer to the matched entry, save pointers to needed variables from this entry and use them after release mutex. Pass argument stored in the encaptab entry to encap_fillarg(), instead of pointer to matched entry. Also do not allocate new mbuf tag, when argument that we plan to save in this tag is NULL. Also make encaptab variable static. Obtained from: Yandex LLC Sponsored by: Yandex LLC Modified: head/sys/netinet/ip_encap.c Modified: head/sys/netinet/ip_encap.c ============================================================================== --- head/sys/netinet/ip_encap.c Thu Jun 18 17:42:24 2015 (r284565) +++ head/sys/netinet/ip_encap.c Thu Jun 18 18:28:38 2015 (r284566) @@ -95,14 +95,14 @@ static MALLOC_DEFINE(M_NETADDR, "encap_e static void encap_add(struct encaptab *); static int mask_match(const struct encaptab *, const struct sockaddr *, const struct sockaddr *); -static void encap_fillarg(struct mbuf *, const struct encaptab *); +static void encap_fillarg(struct mbuf *, void *); /* * All global variables in ip_encap.c are locked using encapmtx. */ static struct mtx encapmtx; MTX_SYSINIT(encapmtx, &encapmtx, "encapmtx", MTX_DEF); -LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(encaptab); +static LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(encaptab); /* * We currently keey encap_init() for source code compatibility reasons -- @@ -122,12 +122,12 @@ encap4_input(struct mbuf **mp, int *offp struct sockaddr_in s, d; const struct protosw *psw; struct encaptab *ep, *match; + void *arg; int matchprio, off, prio; m = *mp; off = *offp; ip = mtod(m, struct ip *); - *mp = NULL; bzero(&s, sizeof(s)); s.sin_family = AF_INET; @@ -138,6 +138,8 @@ encap4_input(struct mbuf **mp, int *offp d.sin_len = sizeof(struct sockaddr_in); d.sin_addr = ip->ip_dst; + arg = NULL; + psw = NULL; match = NULL; matchprio = 0; mtx_lock(&encapmtx); @@ -182,14 +184,16 @@ encap4_input(struct mbuf **mp, int *offp match = ep; } } + if (match != NULL) { + psw = match->psw; + arg = match->arg; + } mtx_unlock(&encapmtx); - if (match) { + if (match != NULL) { /* found a match, "match" has the best one */ - psw = match->psw; - if (psw && psw->pr_input) { - encap_fillarg(m, match); - *mp = m; + if (psw != NULL && psw->pr_input != NULL) { + encap_fillarg(m, arg); (*psw->pr_input)(mp, offp, proto); } else m_freem(m); @@ -197,7 +201,6 @@ encap4_input(struct mbuf **mp, int *offp } /* last resort: inject to raw socket */ - *mp = m; return (rip_input(mp, offp, proto)); } #endif @@ -211,6 +214,7 @@ encap6_input(struct mbuf **mp, int *offp struct sockaddr_in6 s, d; const struct protosw *psw; struct encaptab *ep, *match; + void *arg; int prio, matchprio; ip6 = mtod(m, struct ip6_hdr *); @@ -224,6 +228,8 @@ encap6_input(struct mbuf **mp, int *offp d.sin6_len = sizeof(struct sockaddr_in6); d.sin6_addr = ip6->ip6_dst; + arg = NULL; + psw = NULL; match = NULL; matchprio = 0; mtx_lock(&encapmtx); @@ -251,17 +257,20 @@ encap6_input(struct mbuf **mp, int *offp match = ep; } } + if (match != NULL) { + psw = match->psw; + arg = match->arg; + } mtx_unlock(&encapmtx); - if (match) { + if (match != NULL) { /* found a match */ - psw = match->psw; - if (psw && psw->pr_input) { - encap_fillarg(m, match); + if (psw != NULL && psw->pr_input != NULL) { + encap_fillarg(m, arg); return (*psw->pr_input)(mp, offp, proto); } else { m_freem(m); - return IPPROTO_DONE; + return (IPPROTO_DONE); } } @@ -440,14 +449,16 @@ mask_match(const struct encaptab *ep, co } static void -encap_fillarg(struct mbuf *m, const struct encaptab *ep) +encap_fillarg(struct mbuf *m, void *arg) { struct m_tag *tag; - tag = m_tag_get(PACKET_TAG_ENCAP, sizeof (void*), M_NOWAIT); - if (tag) { - *(void**)(tag+1) = ep->arg; - m_tag_prepend(m, tag); + if (arg != NULL) { + tag = m_tag_get(PACKET_TAG_ENCAP, sizeof(void *), M_NOWAIT); + if (tag != NULL) { + *(void**)(tag+1) = arg; + m_tag_prepend(m, tag); + } } }