]> granicus.if.org Git - libtirpc/commitdiff
Fix xp_raddr handling in svc_fd_create etc
authorOlaf Kirch <okir@suse.de>
Tue, 30 Sep 2008 19:04:17 +0000 (15:04 -0400)
committerSteve Dickson <steved@redhat.com>
Tue, 30 Sep 2008 19:04:17 +0000 (15:04 -0400)
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
src/svc_dg.c
src/svc_vc.c

index 110d35ab78bdc0525bfff0453f2091c771d502eb..a93508000e668de5338d3c1973f54b4cbc54de27 100644 (file)
@@ -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;
index a72abe4106cdf8fb0c2287dd7f8e735983a4fb4c..76a480ebd007595e6e25e24091755b2bef2d1422 100644 (file)
@@ -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)) {
index 3d77aef727cd76d9d40dda74da132cd54ec023b0..c62343b76435037c0010efc4e2ee27031dd26579 100644 (file)
@@ -116,6 +116,29 @@ map_ipv4_to_ipv6(sin, sin6)
        sin6->sin6_addr.s6_addr32[3] = *(uint32_t *)&sin->sin_addr;
 }
 
+/*
+ * 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? */