summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/rpc
diff options
context:
space:
mode:
authorMarcel Telka <marcel@telka.sk>2017-05-24 07:32:14 +0200
committerDan McDonald <danmcd@joyent.com>2017-06-13 10:37:46 -0400
commit6dd72a43d2e43185833c20e7f0c4cb88a4d37ec8 (patch)
tree50d996bddb002bfa4303006fd6c7f40e3c854eb4 /usr/src/uts/common/rpc
parent1d8d40bd3f903c0d0fa71c26b4548d2d47260251 (diff)
downloadillumos-joyent-6dd72a43d2e43185833c20e7f0c4cb88a4d37ec8.tar.gz
8106 authloopback_marshal() can violate the RPC specification
8109 Kernel AUTH_SYS and AUTH_LOOPBACK implementation can ignore provided credentials Reviewed by: Toomas Soome <tsoome@me.com> Reviewed by: Jason King <jason.brian.king+illumos@gmail.com> Approved by: Dan McDonald <danmcd@joyent.com>
Diffstat (limited to 'usr/src/uts/common/rpc')
-rw-r--r--usr/src/uts/common/rpc/auth_sys.h4
-rw-r--r--usr/src/uts/common/rpc/sec/auth_kern.c105
-rw-r--r--usr/src/uts/common/rpc/sec/auth_loopb.c113
-rw-r--r--usr/src/uts/common/rpc/sec/authu_prot.c17
4 files changed, 157 insertions, 82 deletions
diff --git a/usr/src/uts/common/rpc/auth_sys.h b/usr/src/uts/common/rpc/auth_sys.h
index 5f163d270b..ef66402245 100644
--- a/usr/src/uts/common/rpc/auth_sys.h
+++ b/usr/src/uts/common/rpc/auth_sys.h
@@ -116,8 +116,8 @@ extern bool_t xdr_gid_t(XDR *, gid_t *);
extern bool_t xdr_uid_t(XDR *, uid_t *);
#ifdef _KERNEL
-extern bool_t xdr_authkern(XDR *);
-extern bool_t xdr_authloopback(XDR *);
+extern bool_t xdr_authkern(XDR *, cred_t *);
+extern bool_t xdr_authloopback(XDR *, cred_t *);
extern enum auth_stat _svcauth_unix(struct svc_req *, struct rpc_msg *);
extern enum auth_stat _svcauth_short(struct svc_req *, struct rpc_msg *);
#endif
diff --git a/usr/src/uts/common/rpc/sec/auth_kern.c b/usr/src/uts/common/rpc/sec/auth_kern.c
index e045c1c08f..2c3286d35d 100644
--- a/usr/src/uts/common/rpc/sec/auth_kern.c
+++ b/usr/src/uts/common/rpc/sec/auth_kern.c
@@ -120,78 +120,117 @@ authkern_marshal(AUTH *auth, XDR *xdrs, struct cred *cr)
{
char *sercred;
XDR xdrm;
- struct opaque_auth *cred;
- bool_t ret = FALSE;
- const gid_t *gp, *gpend;
- int gidlen, credsize, namelen, rounded_namelen;
+ bool_t ret;
+ uint32_t gidlen, credsize, namelen, rounded_namelen;
int32_t *ptr;
char *nodename = uts_nodename();
+ uint_t startpos;
+
+ ASSERT(xdrs->x_op == XDR_ENCODE);
+ ASSERT(auth->ah_cred.oa_flavor == AUTH_SYS);
+ ASSERT(auth->ah_verf.oa_flavor == AUTH_NONE);
+ ASSERT(auth->ah_verf.oa_length == 0);
/*
* First we try a fast path to get through
* this very common operation.
*/
- gp = crgetgroups(cr);
+ namelen = (uint32_t)strlen(nodename);
+ if (namelen > MAX_MACHINE_NAME)
+ return (FALSE);
+ rounded_namelen = RNDUP(namelen);
+
+ /*
+ * NFIELDS is a number of the following fields we are going to encode:
+ * - stamp
+ * - strlen(machinename)
+ * - uid
+ * - gid
+ * - the number of gids
+ */
+#define NFIELDS 5
+ CTASSERT((NFIELDS + NGRPS) * BYTES_PER_XDR_UNIT +
+ RNDUP(MAX_MACHINE_NAME) <= MAX_AUTH_BYTES);
+
gidlen = crgetngroups(cr);
if (gidlen > NGRPS)
gidlen = NGRPS;
- gpend = &gp[gidlen-1];
- namelen = (int)strlen(nodename);
- rounded_namelen = RNDUP(namelen);
- credsize = 4 + 4 + rounded_namelen + 4 + 4 + 4 + gidlen * 4;
- ptr = XDR_INLINE(xdrs, 4 + 4 + credsize + 4 + 4);
- if (ptr) {
+ credsize = NFIELDS * BYTES_PER_XDR_UNIT + rounded_namelen +
+ gidlen * BYTES_PER_XDR_UNIT;
+ ASSERT(credsize <= MAX_AUTH_BYTES);
+#undef NFIELDS
+
+ /*
+ * We need to marshal both cred and verf parts of the rpc_msg body
+ * (call_body). For the cred part we need to inline the auth_flavor
+ * and the opaque auth body size. Then we inline the credsize bytes of
+ * the opaque auth body for the cred part. Finally we add the
+ * AUTH_NONE verifier (its auth_flavor and the opaque auth body size).
+ */
+ ptr = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT + credsize +
+ 2 * BYTES_PER_XDR_UNIT);
+ if (ptr != NULL) {
/*
* We can do the fast path.
*/
- IXDR_PUT_INT32(ptr, AUTH_UNIX); /* cred flavor */
- IXDR_PUT_INT32(ptr, credsize); /* cred len */
+ const gid_t *gp = crgetgroups(cr);
+
+ IXDR_PUT_U_INT32(ptr, AUTH_SYS); /* cred flavor */
+ IXDR_PUT_U_INT32(ptr, credsize); /* cred len */
+
IXDR_PUT_INT32(ptr, gethrestime_sec());
- IXDR_PUT_INT32(ptr, namelen);
- bcopy(nodename, (caddr_t)ptr, namelen);
- if (rounded_namelen - namelen)
- bzero(((caddr_t)ptr) + namelen,
- rounded_namelen - namelen);
+ IXDR_PUT_U_INT32(ptr, namelen);
+ bcopy(nodename, ptr, namelen);
+ if ((rounded_namelen - namelen) > 0)
+ bzero((char *)ptr + namelen, rounded_namelen - namelen);
ptr += rounded_namelen / BYTES_PER_XDR_UNIT;
- IXDR_PUT_INT32(ptr, crgetuid(cr));
- IXDR_PUT_INT32(ptr, crgetgid(cr));
- IXDR_PUT_INT32(ptr, gidlen);
- while (gp <= gpend) {
- IXDR_PUT_INT32(ptr, *gp++);
- }
- IXDR_PUT_INT32(ptr, AUTH_NULL); /* verf flavor */
- IXDR_PUT_INT32(ptr, 0); /* verf len */
+ IXDR_PUT_U_INT32(ptr, crgetuid(cr));
+ IXDR_PUT_U_INT32(ptr, crgetgid(cr));
+ IXDR_PUT_U_INT32(ptr, gidlen);
+ while (gidlen-- > 0)
+ IXDR_PUT_U_INT32(ptr, *gp++);
+
+ IXDR_PUT_U_INT32(ptr, AUTH_NULL); /* verf flavor */
+ IXDR_PUT_U_INT32(ptr, 0); /* verf len */
+
return (TRUE);
}
+
sercred = kmem_alloc(MAX_AUTH_BYTES, KM_SLEEP);
+
/*
- * serialize u struct stuff into sercred
+ * Serialize the auth body data into sercred.
*/
xdrmem_create(&xdrm, sercred, MAX_AUTH_BYTES, XDR_ENCODE);
- if (!xdr_authkern(&xdrm)) {
+ startpos = XDR_GETPOS(&xdrm);
+ if (!xdr_authkern(&xdrm, cr)) {
printf("authkern_marshal: xdr_authkern failed\n");
ret = FALSE;
goto done;
}
/*
- * Make opaque auth credentials that point at serialized u struct
+ * Make opaque auth credentials to point at the serialized auth body
+ * data.
*/
- cred = &(auth->ah_cred);
- cred->oa_length = XDR_GETPOS(&xdrm);
- cred->oa_base = sercred;
+ auth->ah_cred.oa_base = sercred;
+ auth->ah_cred.oa_length = XDR_GETPOS(&xdrm) - startpos;
+ ASSERT(auth->ah_cred.oa_length <= MAX_AUTH_BYTES);
/*
- * serialize credentials and verifiers (null)
+ * serialize credentials and verifier (null)
*/
if ((xdr_opaque_auth(xdrs, &(auth->ah_cred))) &&
(xdr_opaque_auth(xdrs, &(auth->ah_verf))))
ret = TRUE;
else
ret = FALSE;
+
done:
+ XDR_DESTROY(&xdrm);
kmem_free(sercred, MAX_AUTH_BYTES);
+
return (ret);
}
diff --git a/usr/src/uts/common/rpc/sec/auth_loopb.c b/usr/src/uts/common/rpc/sec/auth_loopb.c
index 8e4e4522ad..ab5318162b 100644
--- a/usr/src/uts/common/rpc/sec/auth_loopb.c
+++ b/usr/src/uts/common/rpc/sec/auth_loopb.c
@@ -32,8 +32,6 @@
* under license from the Regents of the University of California.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* auth_loopb.c, implements UNIX style authentication parameters in the
* kernel. Interfaces with svc_auth_loopback on the server. See
@@ -124,77 +122,120 @@ authloopback_marshal(AUTH *auth, XDR *xdrs, struct cred *cr)
{
char *sercred;
XDR xdrm;
- struct opaque_auth *cred;
- bool_t ret = FALSE;
- const gid_t *gp, *gpend;
- int gidlen, credsize, namelen, rounded_namelen;
+ bool_t ret;
+ uint32_t gidlen, credsize, namelen, rounded_namelen;
int32_t *ptr;
+ char *nodename = uts_nodename();
+ uint32_t maxgidlen;
+ uint_t startpos;
+
+ ASSERT(xdrs->x_op == XDR_ENCODE);
+ ASSERT(auth->ah_cred.oa_flavor == AUTH_LOOPBACK);
+ ASSERT(auth->ah_verf.oa_flavor == AUTH_NONE);
+ ASSERT(auth->ah_verf.oa_length == 0);
/*
* First we try a fast path to get through
* this very common operation.
*/
- gp = crgetgroups(cr);
+ namelen = (uint32_t)strlen(nodename);
+ if (namelen > MAX_MACHINE_NAME)
+ return (FALSE);
+ rounded_namelen = RNDUP(namelen);
+
+ /*
+ * NFIELDS is a number of the following fields we are going to encode:
+ * - stamp
+ * - strlen(machinename)
+ * - uid
+ * - gid
+ * - the number of gids
+ */
+#define NFIELDS 5
+ CTASSERT(NFIELDS * BYTES_PER_XDR_UNIT + RNDUP(MAX_MACHINE_NAME) <=
+ MAX_AUTH_BYTES);
+ maxgidlen = (MAX_AUTH_BYTES - NFIELDS * BYTES_PER_XDR_UNIT -
+ rounded_namelen) / BYTES_PER_XDR_UNIT;
+
gidlen = crgetngroups(cr);
- if (gidlen > NGRPS_LOOPBACK)
+ if (gidlen > maxgidlen)
return (FALSE);
- gpend = &gp[gidlen-1];
- namelen = (int)strlen(uts_nodename());
- rounded_namelen = RNDUP(namelen);
- credsize = 4 + 4 + rounded_namelen + 4 + 4 + 4 + gidlen * 4;
- ptr = XDR_INLINE(xdrs, 4 + 4 + credsize + 4 + 4);
- if (ptr) {
+ credsize = NFIELDS * BYTES_PER_XDR_UNIT + rounded_namelen +
+ gidlen * BYTES_PER_XDR_UNIT;
+ ASSERT(credsize <= MAX_AUTH_BYTES);
+#undef NFIELDS
+
+ /*
+ * We need to marshal both cred and verf parts of the rpc_msg body
+ * (call_body). For the cred part we need to inline the auth_flavor
+ * and the opaque auth body size. Then we inline the credsize bytes of
+ * the opaque auth body for the cred part. Finally we add the
+ * AUTH_NONE verifier (its auth_flavor and the opaque auth body size).
+ */
+ ptr = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT + credsize +
+ 2 * BYTES_PER_XDR_UNIT);
+ if (ptr != NULL) {
/*
* We can do the fast path.
*/
- IXDR_PUT_INT32(ptr, AUTH_LOOPBACK); /* cred flavor */
- IXDR_PUT_INT32(ptr, credsize); /* cred len */
+ const gid_t *gp = crgetgroups(cr);
+
+ IXDR_PUT_U_INT32(ptr, AUTH_LOOPBACK); /* cred flavor */
+ IXDR_PUT_U_INT32(ptr, credsize); /* cred len */
+
IXDR_PUT_INT32(ptr, gethrestime_sec());
- IXDR_PUT_INT32(ptr, namelen);
- bcopy(uts_nodename(), ptr, namelen);
- if (rounded_namelen - namelen)
- bzero(((caddr_t)ptr) + namelen,
- rounded_namelen - namelen);
+ IXDR_PUT_U_INT32(ptr, namelen);
+ bcopy(nodename, ptr, namelen);
+ if ((rounded_namelen - namelen) > 0)
+ bzero((char *)ptr + namelen, rounded_namelen - namelen);
ptr += rounded_namelen / BYTES_PER_XDR_UNIT;
- IXDR_PUT_INT32(ptr, crgetuid(cr));
- IXDR_PUT_INT32(ptr, crgetgid(cr));
- IXDR_PUT_INT32(ptr, gidlen);
- while (gp <= gpend) {
- IXDR_PUT_INT32(ptr, *gp++);
- }
- IXDR_PUT_INT32(ptr, AUTH_NULL); /* verf flavor */
- IXDR_PUT_INT32(ptr, 0); /* verf len */
+ IXDR_PUT_U_INT32(ptr, crgetuid(cr));
+ IXDR_PUT_U_INT32(ptr, crgetgid(cr));
+ IXDR_PUT_U_INT32(ptr, gidlen);
+ while (gidlen-- > 0)
+ IXDR_PUT_U_INT32(ptr, *gp++);
+
+ IXDR_PUT_U_INT32(ptr, AUTH_NONE); /* verf flavor */
+ IXDR_PUT_U_INT32(ptr, 0); /* verf len */
+
return (TRUE);
}
+
sercred = kmem_alloc(MAX_AUTH_BYTES, KM_SLEEP);
+
/*
- * serialize u struct stuff into sercred
+ * Serialize the auth body data into sercred.
*/
xdrmem_create(&xdrm, sercred, MAX_AUTH_BYTES, XDR_ENCODE);
- if (!xdr_authloopback(&xdrm)) {
+ startpos = XDR_GETPOS(&xdrm);
+ if (!xdr_authloopback(&xdrm, cr)) {
printf("authloopback_marshal: xdr_authloopback failed\n");
ret = FALSE;
goto done;
}
/*
- * Make opaque auth credentials that point at serialized u struct
+ * Make opaque auth credentials to point at the serialized auth body
+ * data.
*/
- cred = &(auth->ah_cred);
- cred->oa_length = XDR_GETPOS(&xdrm);
- cred->oa_base = sercred;
+ auth->ah_cred.oa_base = sercred;
+ auth->ah_cred.oa_length = XDR_GETPOS(&xdrm) - startpos;
+ ASSERT(auth->ah_cred.oa_length <= MAX_AUTH_BYTES);
/*
- * serialize credentials and verifiers (null)
+ * serialize credentials and verifier (null)
*/
if ((xdr_opaque_auth(xdrs, &(auth->ah_cred))) &&
(xdr_opaque_auth(xdrs, &(auth->ah_verf))))
ret = TRUE;
else
ret = FALSE;
+
done:
+ XDR_DESTROY(&xdrm);
kmem_free(sercred, MAX_AUTH_BYTES);
+
return (ret);
}
diff --git a/usr/src/uts/common/rpc/sec/authu_prot.c b/usr/src/uts/common/rpc/sec/authu_prot.c
index dbc719e03c..8b0bf90a5d 100644
--- a/usr/src/uts/common/rpc/sec/authu_prot.c
+++ b/usr/src/uts/common/rpc/sec/authu_prot.c
@@ -110,20 +110,18 @@ xdr_gid_t(XDR *xdrs, gid_t *ip)
* NOTE: this is an XDR_ENCODE only routine.
*/
bool_t
-xdr_authkern(XDR *xdrs)
+xdr_authkern(XDR *xdrs, cred_t *cr)
{
uid_t uid;
gid_t gid;
uint_t len;
caddr_t groups;
char *name = uts_nodename();
- struct cred *cr;
time_t now;
if (xdrs->x_op != XDR_ENCODE)
return (FALSE);
- cr = CRED();
uid = crgetuid(cr);
gid = crgetgid(cr);
len = crgetngroups(cr);
@@ -137,8 +135,7 @@ xdr_authkern(XDR *xdrs)
xdr_string(xdrs, &name, MAX_MACHINE_NAME) &&
xdr_uid_t(xdrs, &uid) &&
xdr_gid_t(xdrs, &gid) &&
- xdr_array(xdrs, &groups, &len, NGRPS, sizeof (int),
- (xdrproc_t)xdr_int))
+ xdr_array(xdrs, &groups, &len, NGRPS, sizeof (gid_t), xdr_gid_t))
return (TRUE);
return (FALSE);
}
@@ -148,20 +145,18 @@ xdr_authkern(XDR *xdrs)
* NOTE: this is an XDR_ENCODE only routine.
*/
bool_t
-xdr_authloopback(XDR *xdrs)
+xdr_authloopback(XDR *xdrs, cred_t *cr)
{
uid_t uid;
gid_t gid;
- int len;
+ uint_t len;
caddr_t groups;
char *name = uts_nodename();
- struct cred *cr;
time_t now;
if (xdrs->x_op != XDR_ENCODE)
return (FALSE);
- cr = CRED();
uid = crgetuid(cr);
gid = crgetgid(cr);
len = crgetngroups(cr);
@@ -171,8 +166,8 @@ xdr_authloopback(XDR *xdrs)
xdr_string(xdrs, &name, MAX_MACHINE_NAME) &&
xdr_uid_t(xdrs, &uid) &&
xdr_gid_t(xdrs, &gid) &&
- xdr_array(xdrs, &groups, (uint_t *)&len, NGRPS_LOOPBACK,
- sizeof (int), (xdrproc_t)xdr_int))
+ xdr_array(xdrs, &groups, &len, NGROUPS_UMAX, sizeof (gid_t),
+ xdr_gid_t))
return (TRUE);
return (FALSE);
}