From 92be2847e845ba90e4da028cfd7f5a8013919f90 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Wed, 23 Dec 2020 11:15:11 -0500 Subject: [PATCH] rtsock: Avoid copying uninitialized padding bytes When copying sockaddrs out to userspace, we pad them to a multiple of the platform alignment (sizeof(long)). However, some sockaddr sizes, such as struct sockaddr_dl, are not an integer multiple of the alignment, so we may end up copying out uninitialized bytes. Fix this by always bouncing through a pre-zeroed sockaddr_storage. Reported by: KASAN Reviewed by: melifaro MFC after: 3 days Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D27729 --- sys/net/rtsock.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c index 4c35642866c..5acfd658caf 100644 --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -1258,12 +1258,12 @@ rtsock_fix_netmask(const struct sockaddr *dst, const struct sockaddr *smask, static struct mbuf * rtsock_msg_mbuf(int type, struct rt_addrinfo *rtinfo) { + struct sockaddr_storage ss; struct rt_msghdr *rtm; struct mbuf *m; int i; struct sockaddr *sa; #ifdef INET6 - struct sockaddr_storage ss; struct sockaddr_in6 *sin6; #endif int len, dlen; @@ -1308,13 +1308,17 @@ rtsock_msg_mbuf(int type, struct rt_addrinfo *rtinfo) if ((sa = rtinfo->rti_info[i]) == NULL) continue; rtinfo->rti_addrs |= (1 << i); + dlen = SA_SIZE(sa); + KASSERT(dlen <= sizeof(ss), + ("%s: sockaddr size overflow", __func__)); + bzero(&ss, sizeof(ss)); + bcopy(sa, &ss, sa->sa_len); + sa = (struct sockaddr *)&ss; #ifdef INET6 if (sa->sa_family == AF_INET6) { - sin6 = (struct sockaddr_in6 *)&ss; - bcopy(sa, sin6, sizeof(*sin6)); - if (sa6_recoverscope(sin6) == 0) - sa = (struct sockaddr *)sin6; + sin6 = (struct sockaddr_in6 *)sa; + (void)sa6_recoverscope(sin6); } #endif m_copyback(m, len, dlen, (caddr_t)sa); @@ -1342,12 +1346,11 @@ rtsock_msg_mbuf(int type, struct rt_addrinfo *rtinfo) static int rtsock_msg_buffer(int type, struct rt_addrinfo *rtinfo, struct walkarg *w, int *plen) { - int i; - int len, buflen = 0, dlen; + struct sockaddr_storage ss; + int len, buflen = 0, dlen, i; caddr_t cp = NULL; struct rt_msghdr *rtm = NULL; #ifdef INET6 - struct sockaddr_storage ss; struct sockaddr_in6 *sin6; #endif #ifdef COMPAT_FREEBSD32 @@ -1414,12 +1417,15 @@ rtsock_msg_buffer(int type, struct rt_addrinfo *rtinfo, struct walkarg *w, int * #endif dlen = SA_SIZE(sa); if (cp != NULL && buflen >= dlen) { + KASSERT(dlen <= sizeof(ss), + ("%s: sockaddr size overflow", __func__)); + bzero(&ss, sizeof(ss)); + bcopy(sa, &ss, sa->sa_len); + sa = (struct sockaddr *)&ss; #ifdef INET6 if (sa->sa_family == AF_INET6) { - sin6 = (struct sockaddr_in6 *)&ss; - bcopy(sa, sin6, sizeof(*sin6)); - if (sa6_recoverscope(sin6) == 0) - sa = (struct sockaddr *)sin6; + sin6 = (struct sockaddr_in6 *)sa; + (void)sa6_recoverscope(sin6); } #endif bcopy((caddr_t)sa, cp, (unsigned)dlen);