forked from pool/libtirpc
177 lines
5.1 KiB
Diff
177 lines
5.1 KiB
Diff
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
|
|
|