Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/net Restore the original length of a sockaddr for netmask



details:   https://anonhg.NetBSD.org/src/rev/1b2cede90d78
branches:  trunk
changeset: 825116:1b2cede90d78
user:      ozaki-r <ozaki-r%NetBSD.org@localhost>
date:      Fri Jun 30 09:11:22 2017 +0000

description:
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.

diffstat:

 sys/net/rtsock.c |  42 ++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 40 insertions(+), 2 deletions(-)

diffs (77 lines):

diff -r ccb6ce91948a -r 1b2cede90d78 sys/net/rtsock.c
--- a/sys/net/rtsock.c  Fri Jun 30 09:11:21 2017 +0000
+++ b/sys/net/rtsock.c  Fri Jun 30 09:11:22 2017 +0000
@@ -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 @@
        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 @@
            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 @@
     }
 out:
        curlwp_bindx(bound);
+       if (netmask)
+               sockaddr_free(netmask);
        return error;
 }
 



Home | Main Index | Thread Index | Old Index