Current-Users archive

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

Regression on rtadvd (was: Re: CVS commit: src/usr.sbin/rtadvd)



> Module Name:	src
> Committed By:	roy
> Date:		Fri Jun  5 14:15:41 UTC 2015
> 
> Modified Files:
> 	src/usr.sbin/rtadvd: rtadvd.c
> 
> Log Message:
> Set the hoplimit of 255 as specified in RFC 4861 section 4.2
> using the IPV6_MULTICAST_HOPS socket option rather than using CMSG
> when constructing each message.
This commit broke rtadvd for me, on i386, which now gives "Invalid argument" on the call to sendmsg() that is supposed to generate RAs.

Here's two gdb transcripts:

This is what happens AFTER the offending commit:

| # gdb -q rtadvd
| (gdb) break rtadvd.c:1699
| (gdb) run -df vr1
| [...]
| Breakpoint 1, ra_output (rai=0xbb91c0e0) at /usr/src.head/usr.sbin/rtadvd/rtadvd.c:1699
| 1699		i = sendmsg(sock, &sndmhdr, 0);
| (gdb) bt
| #0  ra_output (rai=0xbb91c0e0) at /usr/src.head/usr.sbin/rtadvd/rtadvd.c:1699
| #1  0x0804cdbf in ra_timeout (data=0xbb91c0e0) at /usr/src.head/usr.sbin/rtadvd/rtadvd.c:1779
| #2  0x08052610 in rtadvd_check_timer () at /usr/src.head/usr.sbin/rtadvd/timer.c:130
| #3  0x080499c0 in main (argc=-1, argv=0xbfbfec64) at /usr/src.head/usr.sbin/rtadvd/rtadvd.c:315
| (gdb) x/28xb &sndmhdr 
| 0x8058b2c <sndmhdr>:    0x40	0x7e	0x05	0x08	0x1c	0x00	0x00	0x00
| 0x8058b34 <sndmhdr+8>:  0xc4	0x8a	0x05	0x08	0x01	0x00	0x00	0x00
| 0x8058b3c <sndmhdr+16>: 0xd0	0xa0	0x90	0xbb	0x30	0x00	0x00	0x00
| 0x8058b44 <sndmhdr+24>: 0x00	0x00	0x00	0x00
| (gdb) n
| 1701		if (i < 0 || (size_t)i != rai->ra_datalen)  {
| (gdb) print i
| $1 = -1
| (gdb) n
| [...]
| rtadvd[3794]: <ra_output> sendmsg on vr1: Invalid argument



The following is what it looked like BEFORE the offending commit:

| # gdb -q rtadvd
| (gdb) break rtadvd.c:1702
| (gdb) run -df vr1
| [...]
| Breakpoint 1, ra_output (rai=0xbb91c0e0) at /usr/src.head/usr.sbin/rtadvd/rtadvd.c:1702
| 1702		i = sendmsg(sock, &sndmhdr, 0);
| (gdb) bt
| #0  ra_output (rai=0xbb91c0e0) at /usr/src.head/usr.sbin/rtadvd/rtadvd.c:1702
| #1  0x0804cdcf in ra_timeout (data=0xbb91c0e0) at /usr/src.head/usr.sbin/rtadvd/rtadvd.c:1782
| #2  0x08052620 in rtadvd_check_timer () at /usr/src.head/usr.sbin/rtadvd/timer.c:130
| #3  0x080499c0 in main (argc=-1, argv=0xbfbfec64) at /usr/src.head/usr.sbin/rtadvd/rtadvd.c:315
| (gdb) x/28xb &sndmhdr
| 0x8058b0c <sndmhdr>:    0x20	0x7e	0x05	0x08	0x1c	0x00	0x00	0x00
| 0x8058b14 <sndmhdr+8>:  0xa4	0x8a	0x05	0x08	0x01	0x00	0x00	0x00
| 0x8058b1c <sndmhdr+16>: 0xd0	0xa0	0x90	0xbb	0x30	0x00	0x00	0x00
| 0x8058b24 <sndmhdr+24>: 0x00	0x00	0x00	0x00
| (gdb) n
| 1704		if (i < 0 || (size_t)i != rai->ra_datalen)  {
| (gdb) print i
| $2 = 56



The difference in the representations of `sndmhdr` are in the 1st and 9th byte, which on i386 correspond to the 1st and 3rd members of struct sndhdr:
|        void            *msg_name;      /* optional address */
| and    struct iovec    *msg_iov;       /* scatter/gather array */


I've manually tracked the failing code path down through the sendmsg system call:
sys/kern/uipc_syscalls.c:620 do_sys_sendmsg_so()  ``error = (*so->so_send)(so, sa, &auio, NULL, control, flags, l);''
sys/kern/uipc_socket.c:1602 sosend()              ``error = (*so->so_proto->pr_usrreqs->pr_send)(so, top, addr, control, l);''
sys/netinet6/raw_ip6.c:891 rip6_send()            ``error = rip6_output(m, so, dst, control);''
sys/netinet6/raw_ip6.c:391 rip6_output()          ``if ((error = ip6_setpktopts(control, &opt, [...]''
sys/netinet6/ip6_output.c:2705 ip6_setpktopts()   ``if (cm->cmsg_len == 0 || cm->cmsg_len > control->m_len)''

The last function is where the EINVAL is produced, due to cm->cmsg_len being zero (in the 2nd iteration of the enclosing loop)
Unfortunately, I couldn't figure out what's supposed to happen there.


Any ideas?


Timo Buhrmester


Home | Main Index | Thread Index | Old Index