Module Name:    src
Committed By:   ozaki-r
Date:           Fri Jun 30 09:11:22 UTC 2017

Modified Files:
        src/sys/net: rtsock.c

Log Message:
Restore the original length of a sockaddr for netmask

route(8) passes a sockaddr for netmask that is truncated with its
prefixlen. However the kernel basically doesn't expect such format
and may read beyond the data. So restore the original length of the
the data at the beginning of the kernel for the rest components.

Failures of ATF tests such as route_flags_blackhole6 should
be fixed.


To generate a diff of this commit:
cvs rdiff -u -r1.224 -r1.225 src/sys/net/rtsock.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net/rtsock.c
diff -u src/sys/net/rtsock.c:1.224 src/sys/net/rtsock.c:1.225
--- src/sys/net/rtsock.c:1.224	Wed Jun 28 04:14:53 2017
+++ src/sys/net/rtsock.c	Fri Jun 30 09:11:22 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: rtsock.c,v 1.224 2017/06/28 04:14:53 ozaki-r Exp $	*/
+/*	$NetBSD: rtsock.c,v 1.225 2017/06/30 09:11:22 ozaki-r Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rtsock.c,v 1.224 2017/06/28 04:14:53 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rtsock.c,v 1.225 2017/06/30 09:11:22 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -736,6 +736,7 @@ COMPATNAME(route_output)(struct mbuf *m,
 	struct sockaddr_dl sdl;
 	int bound = curlwp_bind();
 	bool do_rt_free = false;
+	struct sockaddr *netmask = NULL;
 
 #define senderr(e) do { error = e; goto flush;} while (/*CONSTCOND*/ 0)
 	if (m == NULL || ((m->m_len < sizeof(int32_t)) &&
@@ -793,6 +794,41 @@ COMPATNAME(route_output)(struct mbuf *m,
 	    0, rtm, NULL, NULL) != 0)
 		senderr(EACCES);
 
+	/*
+	 * route(8) passes a sockaddr truncated with prefixlen.
+	 * The kernel doesn't expect such sockaddr and need to restore
+	 * the original length of the sockaddr.
+	 */
+	if (info.rti_info[RTAX_NETMASK]) {
+		size_t sa_len = 0;
+		int af = info.rti_info[RTAX_NETMASK]->sa_family;
+
+		switch (af) {
+#ifdef INET
+		case AF_INET:
+			sa_len = sizeof(struct sockaddr_in);
+			break;
+#endif
+#ifdef INET6
+		case AF_INET6:
+			sa_len = sizeof(struct sockaddr_in6);
+			break;
+#endif
+		default:
+			break;
+		}
+		if (sa_len != 0 &&
+		    sa_len > info.rti_info[RTAX_NETMASK]->sa_len) {
+			netmask = sockaddr_alloc(af, sa_len, M_WAITOK|M_ZERO);
+			sockaddr_copy(netmask,
+			    info.rti_info[RTAX_NETMASK]->sa_len,
+			    info.rti_info[RTAX_NETMASK]);
+			/* Restore original sa_len */
+			netmask->sa_len = info.rti_info[RTAX_NETMASK]->sa_len;
+			info.rti_info[RTAX_NETMASK] = netmask;
+		}
+	}
+
 	switch (rtm->rtm_type) {
 
 	case RTM_ADD:
@@ -1031,6 +1067,8 @@ flush:
     }
 out:
 	curlwp_bindx(bound);
+	if (netmask)
+		sockaddr_free(netmask);
 	return error;
 }
 

Reply via email to