Subject: Bug in routing socket handling
To: None <tech-net@netbsd.org>
From: Tom Ivar Helbekkmo <tih@eunetnorge.no>
List: tech-net
Date: 10/23/2004 14:34:15
I've submitted kern/27286, which includes a patch for a bug in the
kernel's handling of routing socket requests.  The problem is the
special case of an RTM_GET message that wants interface information
included in the response, and therefore include the RTA_IFA or RTA_IFP
(or both) flags in the bitmask that says what addresses are supplied
in the message.  For the RTM_GET message, it doesn't make sense to
supply addresses other than the one you're asking about, so those two
other bits are, in that specific case, overloaded with this meaning.

There is code in sys/net/rtsock.c to handle the case, but at some
time, extra sanity checking of the received message was added, that
failed to take this possibility into account.

The patch, included below, fixes the problem.  I'd very much like to
see it adopted, and included in 2.0, because it's needed for the
Asterisk software PBX to work properly when it has multiple interfaces
active: it needs to ask the kernel for the IP address of the interface
that will be used to communicate with a given host.

Index: sys/net/rtsock.c
===================================================================
RCS file: /cvsroot/src/sys/net/rtsock.c,v
retrieving revision 1.71
diff -u -r1.71 rtsock.c
--- sys/net/rtsock.c	25 May 2004 04:33:59 -0000	1.71
+++ sys/net/rtsock.c	18 Oct 2004 06:47:17 -0000
@@ -100,7 +100,7 @@
 
 static struct mbuf *rt_msg1(int, struct rt_addrinfo *, caddr_t, int);
 static int rt_msg2(int, struct rt_addrinfo *, caddr_t, struct walkarg *, int *);
-static int rt_xaddrs(const char *, const char *, struct rt_addrinfo *);
+static int rt_xaddrs(u_char, const char *, const char *, struct rt_addrinfo *);
 static int sysctl_dumpentry(struct radix_node *, void *);
 static int sysctl_iflist(int, struct walkarg *, int);
 static int sysctl_rtable(SYSCTLFN_PROTO);
@@ -235,7 +235,7 @@
 	rtm->rtm_pid = curproc->p_pid;
 	memset(&info, 0, sizeof(info));
 	info.rti_addrs = rtm->rtm_addrs;
-	if (rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info))
+	if (rt_xaddrs(rtm->rtm_type, (caddr_t)(rtm + 1), len + (caddr_t)rtm, &info))
 		senderr(EINVAL);
 	info.rti_flags = rtm->rtm_flags;
 	if (dst == 0 || (dst->sa_family >= AF_MAX))
@@ -470,7 +470,7 @@
 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
 
 static int
-rt_xaddrs(const char *cp, const char *cplim, struct rt_addrinfo *rtinfo)
+rt_xaddrs(u_char rtmtype, const char *cp, const char *cplim, struct rt_addrinfo *rtinfo)
 {
 	const struct sockaddr *sa = NULL;	/* Quell compiler warning */
 	int i;
@@ -482,9 +482,14 @@
 		ADVANCE(cp, sa);
 	}
 
-	/* Check for extra addresses specified.  */
-	if ((rtinfo->rti_addrs & (~0 << i)) != 0)
-		return (1);
+	/* Check for extra addresses specified, except RTM_GET asking for interface info.  */
+	if (rtmtype == RTM_GET) {
+		if (((rtinfo->rti_addrs & (~((1 << RTAX_IFP) | (1 << RTAX_IFA)))) & (~0 << i)) != 0)
+			return (1);
+	} else {
+		if ((rtinfo->rti_addrs & (~0 << i)) != 0)
+			return (1);
+	}
 	/* Check for bad data length.  */
 	if (cp != cplim) {
 		if (i == RTAX_NETMASK + 1 &&

-tih
-- 
Tom Ivar Helbekkmo, Senior System Administrator, EUnet Norway Hosting
www.eunet.no  T +47-22092958 M +47-93013940 F +47-22092901 FWD 484145