Martin Brandenburg <[email protected]> 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