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

Bug#181701: libc6: sendmsg used incorrectly in sunrpc/svc_udp.c



Package: libc6
Version: 2.2.5-6
Severity: normal
Tags: patch

sunrpc/svc_udp uses sendmsg when sending a reply to a rpc/udb request so
that it can set the source address (using a PKTINFO control message) of the 
reply to match the destination address of the request.  This is good.

The way it does it is to set the IP_PKTINFO option so that recvmsg returns
a PKTINFO control message, and then this control message is passed un-modified
down to sendmsg.  This is wrong.

The PKTINFO control message returned by recvmsg contains an interface index,
a local address and the destination address for the packet.

In the PKTINFO control message accepted by sendmsg, the destination address is
ignored, the local address is used as the source address, and the interface
index is used to force the message to go out that particular interface.

This last is the problem.  By-passing the control packet back unchanged,
the reply is forced to go out the same interface that the request came
in one, even if there is no appropriate route out that interface.

The following patch verifies the existance of a correctly formated PKTINFO
control message, and zeros the ifi_ifindex field.  This means that the reply
will still have the correct source address, but that normally routing decissions
will not be over-ridden.

I have tested this patch on a multi-homed machine that suffered problems with
the current glibc, and it behaves correctly.

This patch is against glibc-2.2.5.  The code in 2.3.1 is largely unchanged.
To make the patch apply, insert '__' before 'recvmsg'.

Thankyou,

NeilBrown


--- sunrpc/svc_udp.c.orig	2003-02-19 11:25:20.000000000 +1100
+++ sunrpc/svc_udp.c	2003-02-19 14:28:46.000000000 +1100
@@ -256,8 +256,26 @@
       mesgp->msg_controllen = sizeof(xprt->xp_pad)
 			      - sizeof (struct iovec) - sizeof (struct msghdr);
       rlen = recvmsg (xprt->xp_sock, mesgp, 0);
-      if (rlen >= 0)
-	len = mesgp->msg_namelen;
+      if (rlen >= 0) {
+	      struct cmsghdr *cmsg;
+	      len = mesgp->msg_namelen;
+	      cmsg = CMSG_FIRSTHDR(mesgp);
+	      if (cmsg == NULL ||
+		  CMSG_NXTHDR(mesgp, cmsg) != NULL ||
+		  cmsg->cmsg_level != SOL_IP ||
+		  cmsg->cmsg_type != IP_PKTINFO ||
+		  cmsg->cmsg_len < sizeof(struct cmsghdr) + sizeof(struct in_pktinfo)) {
+		      /* Not a simple IP_PKTINFO, ignore it */
+		      mesgp->msg_control = NULL;
+		      mesgp->msg_controllen = 0;
+	      } else {
+		      /* it was a simple IP_PKTIFO as we expected,
+		       * Discard the interface field 
+		       */
+		      struct in_pktinfo *pkti = CMSG_DATA(cmsg);
+		      pkti->ipi_ifindex = 0;
+	      }
+      }
     }
   else
 #endif


-- System Information
Debian Release: 3.0
Architecture: i386
Kernel: Linux bartok 2.4.20-server #1 SMP Tue Dec 17 15:40:47 EST 2002 i686
Locale: LANG=C, LC_CTYPE=C




Reply to: