File libtirpc-0.1.9-0005-Fix-xp_raddr-handling-in-svc_fd_create-etc.patch of Package libtirpc

From 59c374c4b507aeca957ed0096d98006edf601375 Mon Sep 17 00:00:00 2001
From: Olaf Kirch <okir@suse.de>
Date: Tue, 30 Sep 2008 15:04:17 -0400
Subject: [PATCH] Fix xp_raddr handling in svc_fd_create etc

Currently svc_fd_create tries to do some clever tricks
with IPv4/v6 address mapping.

This is broken for several reasons.
 1.	We don't want IPv4 based transport to look like IPv6
 	transports. Old applications compiled against tirpc
	will expect AF_INET addresses, and are not equipped
	to deal with AF_INET6.
 2.	There's a buffer overflow.
		memcpy(&sin6, &ss, sizeof(ss));
	copies a full struct sockaddr to a sockaddr_in6 on
	the stack. Unlikely to be exploitable, but I wonder
	if this ever worked....

Signed-off-by: Olaf Kirch <okir@suse.de>
Signed-off-by: Steve Dickson <steved@redhat.com>
---
 src/rpc_com.h |    2 +
 src/svc_dg.c  |    7 +-----
 src/svc_vc.c  |   65 +++++++++++++++++++++++++++-----------------------------
 3 files changed, 34 insertions(+), 40 deletions(-)

diff --git a/src/rpc_com.h b/src/rpc_com.h
index 110d35a..a935080 100644
--- a/src/rpc_com.h
+++ b/src/rpc_com.h
@@ -85,6 +85,8 @@ bool_t __svc_clean_idle(fd_set *, int, bool_t);
 bool_t __xdrrec_setnonblock(XDR *, int);
 bool_t __xdrrec_getrec(XDR *, enum xprt_stat *, bool_t);
 void __xprt_unregister_unlocked(SVCXPRT *);
+void __xprt_set_raddr(SVCXPRT *, const struct sockaddr_storage *);
+
 
 SVCXPRT **__svc_xports;
 int __svc_maxrec;
diff --git a/src/svc_dg.c b/src/svc_dg.c
index a72abe4..76a480e 100644
--- a/src/svc_dg.c
+++ b/src/svc_dg.c
@@ -193,12 +193,7 @@ again:
 		xprt->xp_rtaddr.len = alen;
 	}
 	memcpy(xprt->xp_rtaddr.buf, &ss, alen);
-#ifdef PORTMAP
-	if (ss.ss_family == AF_INET6) {
-		xprt->xp_raddr = *(struct sockaddr_in6 *)xprt->xp_rtaddr.buf;
-		xprt->xp_addrlen = sizeof (struct sockaddr_in6);
-	}
-#endif				/* PORTMAP */
+	__xprt_set_raddr(xprt, &ss);
 	xdrs->x_op = XDR_DECODE;
 	XDR_SETPOS(xdrs, 0);
 	if (! xdr_callmsg(xdrs, msg)) {
diff --git a/src/svc_vc.c b/src/svc_vc.c
index 3d77aef..c62343b 100644
--- a/src/svc_vc.c
+++ b/src/svc_vc.c
@@ -117,6 +117,29 @@ map_ipv4_to_ipv6(sin, sin6)
 }
 
 /*
+ * This is used to set xprt->xp_raddr in a way legacy
+ * apps can deal with
+ */
+void
+__xprt_set_raddr(SVCXPRT *xprt, const struct sockaddr_storage *ss)
+{
+	switch (ss->ss_family) {
+	case AF_INET6:
+		memcpy(&xprt->xp_raddr, ss, sizeof(struct sockaddr_in6));
+		xprt->xp_addrlen = sizeof (struct sockaddr_in6);
+		break;
+	case AF_INET:
+		memcpy(&xprt->xp_raddr, ss, sizeof(struct sockaddr_in));
+		xprt->xp_addrlen = sizeof (struct sockaddr_in);
+		break;
+	default:
+		xprt->xp_raddr.sin6_family = AF_UNSPEC;
+		xprt->xp_addrlen = sizeof (struct sockaddr);
+		break;
+	}
+}
+
+/*
  * Usage:
  *	xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
  *
@@ -201,7 +224,6 @@ svc_fd_create(fd, sendsize, recvsize)
 	u_int recvsize;
 {
 	struct sockaddr_storage ss;
-	struct sockaddr_in6 sin6;
 	socklen_t slen;
 	SVCXPRT *ret;
 
@@ -228,28 +250,16 @@ svc_fd_create(fd, sendsize, recvsize)
 		warnx("svc_fd_create: could not retrieve remote addr");
 		goto freedata;
 	}
-	if (ss.ss_family == AF_INET) {
-		map_ipv4_to_ipv6((struct sockaddr_in *)&ss, &sin6);
-	} else {
-		memcpy(&sin6, &ss, sizeof(ss));
-	}
 	ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = sizeof(ss);
 	ret->xp_rtaddr.buf = mem_alloc((size_t)sizeof(ss));
 	if (ret->xp_rtaddr.buf == NULL) {
 		warnx("svc_fd_create: no mem for local addr");
 		goto freedata;
 	}
-	if (ss.ss_family == AF_INET)
-		memcpy(ret->xp_rtaddr.buf, &ss, (size_t)sizeof(ss));
-	else
-		memcpy(ret->xp_rtaddr.buf, &sin6, (size_t)sizeof(ss));
-#ifdef PORTMAP
-	if (sin6.sin6_family == AF_INET6 || sin6.sin6_family == AF_LOCAL) {
-		memcpy(&ret->xp_raddr, ret->xp_rtaddr.buf,
-			sizeof(struct sockaddr_in6));
-		ret->xp_addrlen = sizeof (struct sockaddr_in6);
-	}
-#endif				/* PORTMAP */
+	memcpy(ret->xp_rtaddr.buf, &ss, (size_t)sizeof(ss));
+
+	/* Set xp_raddr for compatibility */
+	__xprt_set_raddr(ret, &ss);
 
 	return ret;
 
@@ -312,7 +322,6 @@ rendezvous_request(xprt, msg)
 	struct cf_rendezvous *r;
 	struct cf_conn *cd;
 	struct sockaddr_storage addr;
-	struct sockaddr_in6 sin6;
 	socklen_t len;
 	struct __rpc_sockinfo si;
 	SVCXPRT *newxprt;
@@ -344,27 +353,15 @@ again:
 	 */
 
 	newxprt = makefd_xprt(sock, r->sendsize, r->recvsize);
-	if (addr.ss_family == AF_INET) {
-		map_ipv4_to_ipv6((struct sockaddr_in *)&addr, &sin6);
-	} else {
-		memcpy(&sin6, &addr, len);
-	}
 	newxprt->xp_rtaddr.buf = mem_alloc(len);
 	if (newxprt->xp_rtaddr.buf == NULL)
 		return (FALSE);
 
-	if (addr.ss_family == AF_INET)
-		memcpy(newxprt->xp_rtaddr.buf, &addr, len);
-	else
-		memcpy(newxprt->xp_rtaddr.buf, &sin6, len);
+	memcpy(newxprt->xp_rtaddr.buf, &addr, len);
 	newxprt->xp_rtaddr.maxlen = newxprt->xp_rtaddr.len = len;
-#ifdef PORTMAP
-	if (sin6.sin6_family == AF_INET6 || sin6.sin6_family == AF_LOCAL) {
-		memcpy(&newxprt->xp_raddr, newxprt->xp_rtaddr.buf,
-			sizeof(struct sockaddr_in6));
-		newxprt->xp_addrlen = sizeof(struct sockaddr_in6);
-	}
-#endif				/* PORTMAP */
+
+	__xprt_set_raddr(newxprt, &addr);
+
 	if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) {
 		len = 1;
 		/* XXX fvdl - is this useful? */
-- 
1.5.6

openSUSE Build Service is sponsored by