diff options
author | 2019-06-13 08:12:10 +0000 | |
---|---|---|
committer | 2019-06-13 08:12:10 +0000 | |
commit | ff10691ed095a990f60f65135ac291abc7e9c591 (patch) | |
tree | f165631291c09ceda1d39482c2ecebee6be4a46c /sys | |
parent | Add more options to pkcs12 and smime in appstest.sh (diff) | |
download | wireguard-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.c | 75 | ||||
-rw-r--r-- | sys/netinet/in_proto.c | 3 | ||||
-rw-r--r-- | sys/netinet6/in6_proto.c | 3 | ||||
-rw-r--r-- | sys/netmpls/mpls_proto.c | 3 | ||||
-rw-r--r-- | sys/sys/domain.h | 3 |
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 *); |