Martin Brandenburg <mar...@martinbrandenburg.com> writes:

> On a PandaBoard (armv7) running -current, when I run rtadvd, it crashes
> with a bus error shortly after printing (received a routing message). I
> can reproduce by sending SIGHUP to a dhclient running on the same
> interface.
>
> I have traced this down to the following block of code in rtadvd.c.
>
>       static void
>       rtmsg_input(void)
>       {
>               int n, type, ifindex = 0, plen;
>               size_t len;
>               char msg[2048], *next, *lim;
>               u_char ifname[IF_NAMESIZE];
>               struct prefix *prefix;
>               struct rainfo *rai;
>               struct in6_addr *addr;
>               char addrbuf[INET6_ADDRSTRLEN];
>
> So msg is not 32-bit aligned, presumably because INET6_ADDRSTRLEN is 46.
> I can fix the bus error by hardcoding 48, but of course that's not
> right.
>
> Then msg is passed to get_next_msg (as next) where the expression
> rtm->rtm_hdrlen (rtm is the not-aligned msg) is the first dereference
> and thus the point where it crashes.
>
> I'm at the point now where I think I've found the root of the problem
> but don't know enough to fix it.
>
> Any thoughts?

Thanks for the report.

I guess that we could fix the rtm_* functions to work on an unaligned
input buffer, but an easier fix would be to just ask for a suitably
aligned input buffer, with malloc(3).  Does the diff below fix your
problem?

The

-                       addr = get_addr(msg);
-                       plen = get_prefixlen(msg);
+                       addr = get_addr(next);
+                       plen = get_prefixlen(next);

hunks are a potential bugfix.  In my tests the RTM_ADD/DELETE notices
seem to be received "alone" by read(2).  I don't know to which extent
this is a valid assumption, but the fix is included below anyway, to be
committed first, separately.

ok?


Index: rtadvd.c
===================================================================
RCS file: /cvs/src/usr.sbin/rtadvd/rtadvd.c,v
retrieving revision 1.79
diff -u -p -p -u -r1.79 rtadvd.c
--- rtadvd.c    15 Sep 2016 16:16:03 -0000      1.79
+++ rtadvd.c    18 Sep 2016 21:14:51 -0000
@@ -73,6 +73,8 @@ static size_t sndcmsgbuflen;
 struct msghdr sndmhdr;
 struct iovec rcviov[2];
 struct iovec sndiov[2];
+static char *rtsockbuf;
+static size_t rtsockbuflen;
 struct sockaddr_in6 from;
 struct sockaddr_in6 sin6_allnodes = {sizeof(sin6_allnodes), AF_INET6};
 int sock;
@@ -301,17 +303,17 @@ rtsock_cb(int fd, short event, void *arg
 {
        int n, type, ifindex = 0, plen;
        size_t len;
-       char msg[2048], *next, *lim;
+       char *next, *lim;
        u_char ifname[IF_NAMESIZE];
        struct prefix *prefix;
        struct rainfo *rai;
        struct in6_addr *addr;
        char addrbuf[INET6_ADDRSTRLEN];
 
-       n = read(rtsock, msg, sizeof(msg));
+       n = read(rtsock, rtsockbuf, rtsockbuflen);
        log_debug("received a routing message "
-           "(type = %d, len = %d)", rtmsg_type(msg), n);
-       if (n > rtmsg_len(msg)) {
+           "(type = %d, len = %d)", rtmsg_type(rtsockbuf), n);
+       if (n > rtmsg_len(rtsockbuf)) {
                /*
                 * This usually won't happen for messages received on
                 * a routing socket.
@@ -319,15 +321,15 @@ rtsock_cb(int fd, short event, void *arg
                log_debug("received data length is larger than "
                    "1st routing message len. multiple messages? "
                    "read %d bytes, but 1st msg len = %d",
-                   n, rtmsg_len(msg));
+                   n, rtmsg_len(rtsockbuf));
 #if 0
                /* adjust length */
-               n = rtmsg_len(msg);
+               n = rtmsg_len(rtsockbuf);
 #endif
        }
 
-       lim = msg + n;
-       for (next = msg; next < lim; next += len) {
+       lim = rtsockbuf + n;
+       for (next = rtsockbuf; next < lim; next += len) {
                int oldifflags;
 
                next = get_next_msg(next, lim, &len);
@@ -371,8 +373,8 @@ rtsock_cb(int fd, short event, void *arg
                        if (sflag)
                                break;  /* we aren't interested in prefixes  */
 
-                       addr = get_addr(msg);
-                       plen = get_prefixlen(msg);
+                       addr = get_addr(next);
+                       plen = get_prefixlen(next);
                        /* sanity check for plen */
                        /* as RFC2373, prefixlen is at least 4 */
                        if (plen < 4 || plen > 127) {
@@ -400,8 +402,8 @@ rtsock_cb(int fd, short event, void *arg
                        if (sflag)
                                break;
 
-                       addr = get_addr(msg);
-                       plen = get_prefixlen(msg);
+                       addr = get_addr(next);
+                       plen = get_prefixlen(next);
                        /* sanity check for plen */
                        /* as RFC2373, prefixlen is at least 4 */
                        if (plen < 4 || plen > 127) {
@@ -1189,6 +1191,11 @@ rtsock_open(void)
        if (setsockopt(rtsock, PF_ROUTE, ROUTE_MSGFILTER,
            &rtfilter, sizeof(rtfilter)) == -1)
                fatal("setsockopt(ROUTE_MSGFILTER)");
+
+       rtsockbuflen = 2048;
+       rtsockbuf = malloc(rtsockbuflen);
+       if (rtsockbuf == NULL)
+               fatal(NULL);
 }
 
 static struct rainfo *

-- 
jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF  DDCC 0DFA 74AE 1524 E7EE

Reply via email to