]> xenbits.xensource.com Git - people/julieng/freebsd.git/commitdiff
The Sun RPC framework uses a netbuf structure to represent the
authordelphij <delphij@FreeBSD.org>
Tue, 29 Sep 2015 18:05:54 +0000 (18:05 +0000)
committerdelphij <delphij@FreeBSD.org>
Tue, 29 Sep 2015 18:05:54 +0000 (18:05 +0000)
transport specific form of a universal transport address.  The
structure is expected to be opaque to consumers.  In the current
implementation, the structure contains a pointer to a buffer
that holds the actual address.

In rpcbind(8), netbuf structures are copied directly, which would
result in two netbuf structures that reference to one shared
address buffer.  When one of the two netbuf structures is freed,
access to the other netbuf structure would result in an undefined
result that may crash the rpcbind(8) daemon.

Fix this by making a copy of the buffer that is going to be freed
instead of doing a shallow copy.

Security: FreeBSD-SA-15:24.rpcbind
Security: CVE-2015-7236

usr.sbin/rpcbind/rpcb_svc_com.c

index a362c8509a42c99fd356583671db797fc5ed1fa7..a88f61947f9666cda846d7da5f95201aed501f96 100644 (file)
@@ -47,6 +47,7 @@
 #include <rpc/rpc.h>
 #include <rpc/rpcb_prot.h>
 #include <rpc/svc_dg.h>
+#include <assert.h>
 #include <netconfig.h>
 #include <errno.h>
 #include <syslog.h>
@@ -1047,19 +1048,31 @@ netbufcmp(struct netbuf *n1, struct netbuf *n2)
        return ((n1->len != n2->len) || memcmp(n1->buf, n2->buf, n1->len));
 }
 
+static bool_t
+netbuf_copybuf(struct netbuf *dst, const struct netbuf *src)
+{
+
+       assert(dst->buf == NULL);
+
+       if ((dst->buf = malloc(src->len)) == NULL)
+               return (FALSE);
+
+       dst->maxlen = dst->len = src->len;
+       memcpy(dst->buf, src->buf, src->len);
+       return (TRUE);
+}
+
 static struct netbuf *
 netbufdup(struct netbuf *ap)
 {
        struct netbuf  *np;
 
-       if ((np = malloc(sizeof(struct netbuf))) == NULL)
+       if ((np = calloc(1, sizeof(struct netbuf))) == NULL)
                return (NULL);
-       if ((np->buf = malloc(ap->len)) == NULL) {
+       if (netbuf_copybuf(np, ap) == FALSE) {
                free(np);
                return (NULL);
        }
-       np->maxlen = np->len = ap->len;
-       memcpy(np->buf, ap->buf, ap->len);
        return (np);
 }
 
@@ -1067,6 +1080,7 @@ static void
 netbuffree(struct netbuf *ap)
 {
        free(ap->buf);
+       ap->buf = NULL;
        free(ap);
 }
 
@@ -1184,7 +1198,7 @@ xprt_set_caller(SVCXPRT *xprt, struct finfo *fi)
 {
        u_int32_t *xidp;
 
-       *(svc_getrpccaller(xprt)) = *(fi->caller_addr);
+       netbuf_copybuf(svc_getrpccaller(xprt), fi->caller_addr);
        xidp = __rpcb_get_dg_xidp(xprt);
        *xidp = fi->caller_xid;
 }