summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorclaudio <claudio@openbsd.org>2019-06-13 08:12:10 +0000
committerclaudio <claudio@openbsd.org>2019-06-13 08:12:10 +0000
commitff10691ed095a990f60f65135ac291abc7e9c591 (patch)
treef165631291c09ceda1d39482c2ecebee6be4a46c /sys
parentAdd more options to pkcs12 and smime in appstest.sh (diff)
downloadwireguard-openbsd-ff10691ed095a990f60f65135ac291abc7e9c591.tar.xz
wireguard-openbsd-ff10691ed095a990f60f65135ac291abc7e9c591.zip
Copy the user provided sockaddr into a normalized sockaddr in rtrequest()
before adding it to the routing table. The rtable code is doing memcmp() of those rt_dest sockaddrs so it is important that they are stored in a canonical form. To do this struct domain is extended to include the sockaddr size for this address family. OK bluhm@ anton@ Reported-by: syzbot+10fe9cd8d0211c562ead@syzkaller.appspotmail.com
Diffstat (limited to 'sys')
-rw-r--r--sys/net/route.c75
-rw-r--r--sys/netinet/in_proto.c3
-rw-r--r--sys/netinet6/in6_proto.c3
-rw-r--r--sys/netmpls/mpls_proto.c3
-rw-r--r--sys/sys/domain.h3
5 files changed, 67 insertions, 20 deletions
diff --git a/sys/net/route.c b/sys/net/route.c
index d6fa43f979b..2cde81661a7 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: route.c,v 1.384 2019/05/11 16:47:02 claudio Exp $ */
+/* $OpenBSD: route.c,v 1.385 2019/06/13 08:12:10 claudio Exp $ */
/* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */
/*
@@ -161,6 +161,7 @@ int rt_ifa_purge_walker(struct rtentry *, void *, unsigned int);
struct rtentry *rt_match(struct sockaddr *, uint32_t *, int, unsigned int);
int rt_clone(struct rtentry **, struct sockaddr *, unsigned int);
struct sockaddr *rt_plentosa(sa_family_t, int, struct sockaddr_in6 *);
+static int rt_copysa(struct sockaddr *, struct sockaddr *, struct sockaddr **);
#ifdef DDB
void db_print_sa(struct sockaddr *);
@@ -809,7 +810,7 @@ rtrequest(int req, struct rt_addrinfo *info, u_int8_t prio,
struct sockaddr *ndst;
struct sockaddr_rtlabel *sa_rl, sa_rl2;
struct sockaddr_dl sa_dl = { sizeof(sa_dl), AF_LINK };
- int dlen, error;
+ int error;
NET_ASSERT_LOCKED();
@@ -843,20 +844,14 @@ rtrequest(int req, struct rt_addrinfo *info, u_int8_t prio,
if (prio == 0)
prio = ifp->if_priority + RTP_STATIC;
- dlen = info->rti_info[RTAX_DST]->sa_len;
- ndst = malloc(dlen, M_RTABLE, M_NOWAIT);
- if (ndst == NULL)
- return (ENOBUFS);
-
- if (info->rti_info[RTAX_NETMASK] != NULL)
- rt_maskedcopy(info->rti_info[RTAX_DST], ndst,
- info->rti_info[RTAX_NETMASK]);
- else
- memcpy(ndst, info->rti_info[RTAX_DST], dlen);
+ error = rt_copysa(info->rti_info[RTAX_DST],
+ info->rti_info[RTAX_NETMASK], &ndst);
+ if (error)
+ return (error);
rt = pool_get(&rtentry_pool, PR_NOWAIT | PR_ZERO);
if (rt == NULL) {
- free(ndst, M_RTABLE, dlen);
+ free(ndst, M_RTABLE, ndst->sa_len);
return (ENOBUFS);
}
@@ -888,7 +883,7 @@ rtrequest(int req, struct rt_addrinfo *info, u_int8_t prio,
error = rt_mpls_set(rt, info->rti_info[RTAX_SRC],
info->rti_mpls);
if (error) {
- free(ndst, M_RTABLE, dlen);
+ free(ndst, M_RTABLE, ndst->sa_len);
pool_put(&rtentry_pool, rt);
return (error);
}
@@ -920,7 +915,7 @@ rtrequest(int req, struct rt_addrinfo *info, u_int8_t prio,
rtfree(rt->rt_parent);
rt_putgwroute(rt);
free(rt->rt_gateway, M_RTABLE, 0);
- free(ndst, M_RTABLE, dlen);
+ free(ndst, M_RTABLE, ndst->sa_len);
pool_put(&rtentry_pool, rt);
return (error);
}
@@ -951,7 +946,7 @@ rtrequest(int req, struct rt_addrinfo *info, u_int8_t prio,
rtfree(rt->rt_parent);
rt_putgwroute(rt);
free(rt->rt_gateway, M_RTABLE, 0);
- free(ndst, M_RTABLE, dlen);
+ free(ndst, M_RTABLE, ndst->sa_len);
pool_put(&rtentry_pool, rt);
return (EEXIST);
}
@@ -1029,6 +1024,54 @@ rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst,
bzero(cp2, cplim2 - cp2);
}
+/*
+ * allocate new sockaddr structure based on the user supplied src and mask
+ * that is useable for the routing table.
+ */
+static int
+rt_copysa(struct sockaddr *src, struct sockaddr *mask, struct sockaddr **dst)
+{
+ static const u_char maskarray[] = {
+ 0x0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
+ struct sockaddr *ndst;
+ struct domain *dp;
+ u_char *csrc, *cdst;
+ int i, plen;
+
+ for (i = 0; (dp = domains[i]) != NULL; i++) {
+ if (dp->dom_rtoffset == 0)
+ continue;
+ if (src->sa_family == dp->dom_family)
+ break;
+ }
+ if (dp == NULL)
+ return (EAFNOSUPPORT);
+
+ if (src->sa_len < dp->dom_sasize)
+ return (EINVAL);
+
+ plen = rtable_satoplen(src->sa_family, mask);
+ if (plen == -1)
+ return (EINVAL);
+
+ ndst = malloc(dp->dom_sasize, M_RTABLE, M_NOWAIT|M_ZERO);
+ if (ndst == NULL)
+ return (ENOBUFS);
+
+ ndst->sa_family = src->sa_family;
+ ndst->sa_len = dp->dom_sasize;
+
+ csrc = (u_char *)src + dp->dom_rtoffset;
+ cdst = (u_char *)ndst + dp->dom_rtoffset;
+
+ memcpy(cdst, csrc, plen / 8);
+ if (plen % 8 != 0)
+ cdst[plen / 8] = csrc[plen / 8] & maskarray[plen % 8];
+
+ *dst = ndst;
+ return (0);
+}
+
int
rt_ifa_add(struct ifaddr *ifa, int flags, struct sockaddr *dst,
unsigned int rdomain)
diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c
index da4a5d8034b..66487b361a8 100644
--- a/sys/netinet/in_proto.c
+++ b/sys/netinet/in_proto.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_proto.c,v 1.91 2018/11/19 10:15:04 claudio Exp $ */
+/* $OpenBSD: in_proto.c,v 1.92 2019/06/13 08:12:11 claudio Exp $ */
/* $NetBSD: in_proto.c,v 1.14 1996/02/18 18:58:32 christos Exp $ */
/*
@@ -443,6 +443,7 @@ struct domain inetdomain = {
.dom_name = "internet",
.dom_protosw = inetsw,
.dom_protoswNPROTOSW = &inetsw[nitems(inetsw)],
+ .dom_sasize = sizeof(struct sockaddr_in),
.dom_rtoffset = offsetof(struct sockaddr_in, sin_addr),
.dom_maxplen = 32
};
diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c
index 3667fe75079..11b63efa566 100644
--- a/sys/netinet6/in6_proto.c
+++ b/sys/netinet6/in6_proto.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in6_proto.c,v 1.103 2018/11/19 10:15:04 claudio Exp $ */
+/* $OpenBSD: in6_proto.c,v 1.104 2019/06/13 08:12:11 claudio Exp $ */
/* $KAME: in6_proto.c,v 1.66 2000/10/10 15:35:47 itojun Exp $ */
/*
@@ -366,6 +366,7 @@ struct domain inet6domain = {
.dom_name = "internet6",
.dom_protosw = inet6sw,
.dom_protoswNPROTOSW = &inet6sw[nitems(inet6sw)],
+ .dom_sasize = sizeof(struct sockaddr_in6),
.dom_rtoffset = offsetof(struct sockaddr_in6, sin6_addr),
.dom_maxplen = 128,
.dom_ifattach = in6_domifattach,
diff --git a/sys/netmpls/mpls_proto.c b/sys/netmpls/mpls_proto.c
index e191c4cabc4..8be741a0c43 100644
--- a/sys/netmpls/mpls_proto.c
+++ b/sys/netmpls/mpls_proto.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mpls_proto.c,v 1.17 2018/11/19 10:15:04 claudio Exp $ */
+/* $OpenBSD: mpls_proto.c,v 1.18 2019/06/13 08:12:11 claudio Exp $ */
/*
* Copyright (C) 1999, 2000 and 2001 AYAME Project, WIDE Project.
@@ -48,6 +48,7 @@
struct domain mplsdomain = {
.dom_family = AF_MPLS,
.dom_name = "mpls",
+ .dom_sasize = sizeof(struct sockaddr_mpls),
.dom_rtoffset = offsetof(struct sockaddr_mpls, smpls_label),
.dom_maxplen = 32
};
diff --git a/sys/sys/domain.h b/sys/sys/domain.h
index 8359cfa3329..7614cfa02b6 100644
--- a/sys/sys/domain.h
+++ b/sys/sys/domain.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: domain.h,v 1.19 2018/11/19 10:15:04 claudio Exp $ */
+/* $OpenBSD: domain.h,v 1.20 2019/06/13 08:12:11 claudio Exp $ */
/* $NetBSD: domain.h,v 1.10 1996/02/09 18:25:07 christos Exp $ */
/*
@@ -57,6 +57,7 @@ struct domain {
void (*dom_dispose)(struct mbuf *);
const struct protosw *dom_protosw, *dom_protoswNPROTOSW;
/* initialize routing table */
+ unsigned int dom_sasize; /* size of sockaddr structure */
unsigned int dom_rtoffset; /* offset of the key, in bytes */
unsigned int dom_maxplen; /* maxium prefix length, in bits */
void *(*dom_ifattach)(struct ifnet *);