svn commit: r284566 - head/sys/netinet
Andrey V. Elsukov
ae at FreeBSD.org
Thu Jun 18 18:28:39 UTC 2015
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);
+ }
}
}
More information about the svn-src-all
mailing list