Hi,

The kernel may crash as there is not enough input validation in
routing messages.

https://syzkaller.appspot.com/bug?id=e2076a6518b49730aefe64acf0a266f8e79685a5

Here the name of a routing label is not NUL terminated, but there
are more things that can go wrong.  So I added some checks for
incoming routing addresses from userland that the kernel actually
uses.

It is not super strict as userland may provide incomplete addresses
that work anyway.  I remember openvpn caused some problems in this
area.  Could someone test it with this diff?

ok?

bluhm

Index: net/rtsock.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/rtsock.c,v
retrieving revision 1.290
diff -u -p -w -r1.290 rtsock.c
--- net/rtsock.c        28 Aug 2019 20:54:24 -0000      1.290
+++ net/rtsock.c        28 Aug 2019 21:23:34 -0000
@@ -1366,6 +1366,91 @@ rtm_xaddrs(caddr_t cp, caddr_t cplim, st
                rtinfo->rti_info[i] = sa;
                ADVANCE(cp, sa);
        }
+       for (i = 0; i < RTAX_MAX; i++) {
+               size_t len, maxlen, size;
+
+               sa = rtinfo->rti_info[i];
+               if (sa == NULL)
+                       continue;
+               maxlen = size = 0;
+               switch (i) {
+               case RTAX_DST:
+               case RTAX_GATEWAY:
+               case RTAX_SRC:
+                       switch (sa->sa_family) {
+                       case AF_INET:
+                               size = sizeof(struct sockaddr_in);
+                               break;
+#ifdef INET6
+                       case AF_INET6:
+                               size = sizeof(struct sockaddr_in6);
+                               break;
+#endif
+#ifdef MPLS
+                       case AF_MPLS:
+                               size = sizeof(struct sockaddr_mpls);
+                               break;
+#endif
+                       }
+                       break;
+               case RTAX_IFP:
+                       if (sa->sa_family != AF_LINK)
+                               return (EAFNOSUPPORT);
+                       /*
+                        * XXX Should be sizeof(struct sockaddr_dl), but
+                        * route(8) has a bug and provides less memory.
+                        */
+                       size = 16;
+                       break;
+               case RTAX_IFA:
+                       switch (sa->sa_family) {
+                       case AF_INET:
+                               size = sizeof(struct sockaddr_in);
+                               break;
+#ifdef INET6
+                       case AF_INET6:
+                               size = sizeof(struct sockaddr_in6);
+                               break;
+#endif
+                       default:
+                               return (EAFNOSUPPORT);
+                       }
+                       break;
+               case RTAX_LABEL:
+                       maxlen = RTLABEL_LEN;
+                       size = sizeof(struct sockaddr_rtlabel);
+                       break;
+#ifdef BFD
+               case RTAX_BFD:
+                       size = sizeof(struct sockaddr_bfd);
+                       break;
+#endif
+               case RTAX_DNS:
+                       maxlen = RTDNS_LEN;
+                       size = sizeof(struct sockaddr_rtdns);
+                       break;
+               case RTAX_STATIC:
+                       maxlen = RTSTATIC_LEN;
+                       size = sizeof(struct sockaddr_rtstatic);
+                       break;
+               case RTAX_SEARCH:
+                       maxlen = RTSEARCH_LEN;
+                       size = sizeof(struct sockaddr_rtsearch);
+                       break;
+               }
+               if (size) {
+                       if (sa->sa_len < size)
+                               return (EINVAL);
+               }
+               if (maxlen) {
+                       if (2 + maxlen >= size)
+                               return (EINVAL);
+                       len = strnlen(sa->sa_data, maxlen);
+                       if (len >= maxlen || 2 + len >= sa->sa_len)
+                               return (EINVAL);
+                       break;
+               }
+       }
        return (0);
 }

Reply via email to