diff options
author | Mark Johnston <markj@FreeBSD.org> | 2020-12-23 16:15:11 +0000 |
---|---|---|
committer | Mark Johnston <markj@FreeBSD.org> | 2020-12-23 16:16:40 +0000 |
commit | 92be2847e845ba90e4da028cfd7f5a8013919f90 (patch) | |
tree | 3901d13019e6884d180556251e99d2525dc3a17f /sys | |
parent | a7a7c306bfb0d8d1a83569a098cf6cde492f8bf7 (diff) | |
download | src-test-92be2847e845ba90e4da028cfd7f5a8013919f90.tar.gz src-test-92be2847e845ba90e4da028cfd7f5a8013919f90.zip |
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
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net/rtsock.c | 30 |
1 files changed, 18 insertions, 12 deletions
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c index 4c35642866c9f..5acfd658caf60 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); |