Subject: kern/27286: Routing socket RTM_GET handling is broken
To: None <gnats-bugs@gnats.NetBSD.org>
From: None <tih@eunetnorge.no>
List: netbsd-bugs
Date: 10/18/2004 11:17:08
>Number:         27286
>Category:       kern
>Synopsis:       Routing socket fails to handle RTM_GET with RTA_IFA/RTA_IFP
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Oct 18 09:18:00 UTC 2004
>Closed-Date:
>Last-Modified:
>Originator:     Tom Ivar Helbekkmo
>Release:        NetBSD 2.99.10
>Organization:
Tom Ivar Helbekkmo, Senior System Administrator, EUnet Norway Hosting
www.eunet.no  T +47-22092958 M +47-93013940 F +47-22092901 FWD 484145
>Environment:
System: NetBSD athene.i.eunet.no 2.99.10 NetBSD 2.99.10 (ATHENE) #15: Mon Oct 18 08:41:18 CEST 2004 root@athene.i.eunet.no:/sys/arch/i386/compile/obj.i386/ATHENE i386
Architecture: i386
Machine: i386
>Description:
Working with Asterisk (the open source IP telephony PBX) under
NetBSD-current, I've discovered that the routing socket handling in
sys/net/rtsock.c is slightly broken.  Specifically, it goes a bit too
far in its parameter checking, disallowing the old hack where an
RTM_GET (which can really only take one parameter, the destination
address) claims to supply interface information as well -- but what
this means, in that specific case, is that the client wants the kernel
to supply that information in the response message.

The code to do the work is present in rtsock.c, but sanity checking of
the request message prevents it from being invoked.  I've modified my
rtsock.c locally as per the accompanying patch, and verified that it
then works as expected.
>How-To-Repeat:
Send a message to the routing socket asking for a route (rtm_type is
RTM_GET), but instead of just setting the rtm_addr field to RTA_DST
(informing the socket handler that a destination address is supplied),
add the RTA_IFA or RTA_IFP bits.  Observe that the request fails with
EINVAL, because the sanity checking does not see the accompanying
data, and fails to take into account the fact that RTM_GET is special.
>Fix:
I've made it work locally, by modifying rtsock.c thus:

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 &&

>Release-Note:
>Audit-Trail:
>Unformatted: