The Sun RPC framework uses a netbuf structure to represent the

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
This commit is contained in:
Xin LI 2015-09-29 18:05:54 +00:00
parent b95523e859
commit 066c492a77
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=288383

View 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;
}