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