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
This commit is contained in:
Mark Johnston 2020-12-23 11:15:11 -05:00
parent a7a7c306bf
commit 92be2847e8

View File

@ -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);