NFSD: Replace READ* macros in nfsd4_decode_cb_sec()

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
Chuck Lever 2020-11-03 13:09:34 -05:00
parent a4a80c15ca
commit 1a99440807
1 changed files with 107 additions and 58 deletions

View File

@ -212,6 +212,25 @@ static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes)
* NFSv4 basic data type decoders
*/
/*
* This helper handles variable-length opaques which belong to protocol
* elements that this implementation does not support.
*/
static __be32
nfsd4_decode_ignored_string(struct nfsd4_compoundargs *argp, u32 maxlen)
{
u32 len;
if (xdr_stream_decode_u32(argp->xdr, &len) < 0)
return nfserr_bad_xdr;
if (maxlen && len > maxlen)
return nfserr_bad_xdr;
if (!xdr_inline_decode(argp->xdr, len))
return nfserr_bad_xdr;
return nfs_ok;
}
static __be32
nfsd4_decode_opaque(struct nfsd4_compoundargs *argp, struct xdr_netobj *o)
{
@ -645,87 +664,117 @@ nfsd4_decode_state_owner4(struct nfsd4_compoundargs *argp,
return nfsd4_decode_opaque(argp, owner);
}
static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs)
/* Defined in Appendix A of RFC 5531 */
static __be32
nfsd4_decode_authsys_parms(struct nfsd4_compoundargs *argp,
struct nfsd4_cb_sec *cbs)
{
DECODE_HEAD;
struct user_namespace *userns = nfsd_user_namespace(argp->rqstp);
u32 dummy, uid, gid;
char *machine_name;
int i;
int nr_secflavs;
u32 stamp, gidcount, uid, gid;
__be32 *p, status;
if (xdr_stream_decode_u32(argp->xdr, &stamp) < 0)
return nfserr_bad_xdr;
/* machine name */
status = nfsd4_decode_ignored_string(argp, 255);
if (status)
return status;
if (xdr_stream_decode_u32(argp->xdr, &uid) < 0)
return nfserr_bad_xdr;
if (xdr_stream_decode_u32(argp->xdr, &gid) < 0)
return nfserr_bad_xdr;
if (xdr_stream_decode_u32(argp->xdr, &gidcount) < 0)
return nfserr_bad_xdr;
if (gidcount > 16)
return nfserr_bad_xdr;
p = xdr_inline_decode(argp->xdr, gidcount << 2);
if (!p)
return nfserr_bad_xdr;
if (cbs->flavor == (u32)(-1)) {
struct user_namespace *userns = nfsd_user_namespace(argp->rqstp);
kuid_t kuid = make_kuid(userns, uid);
kgid_t kgid = make_kgid(userns, gid);
if (uid_valid(kuid) && gid_valid(kgid)) {
cbs->uid = kuid;
cbs->gid = kgid;
cbs->flavor = RPC_AUTH_UNIX;
} else {
dprintk("RPC_AUTH_UNIX with invalid uid or gid, ignoring!\n");
}
}
return nfs_ok;
}
static __be32
nfsd4_decode_gss_cb_handles4(struct nfsd4_compoundargs *argp,
struct nfsd4_cb_sec *cbs)
{
__be32 status;
u32 service;
dprintk("RPC_AUTH_GSS callback secflavor not supported!\n");
if (xdr_stream_decode_u32(argp->xdr, &service) < 0)
return nfserr_bad_xdr;
if (service < RPC_GSS_SVC_NONE || service > RPC_GSS_SVC_PRIVACY)
return nfserr_bad_xdr;
/* gcbp_handle_from_server */
status = nfsd4_decode_ignored_string(argp, 0);
if (status)
return status;
/* gcbp_handle_from_client */
status = nfsd4_decode_ignored_string(argp, 0);
if (status)
return status;
return nfs_ok;
}
/* a counted array of callback_sec_parms4 items */
static __be32
nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs)
{
u32 i, secflavor, nr_secflavs;
__be32 status;
/* callback_sec_params4 */
READ_BUF(4);
nr_secflavs = be32_to_cpup(p++);
if (xdr_stream_decode_u32(argp->xdr, &nr_secflavs) < 0)
return nfserr_bad_xdr;
if (nr_secflavs)
cbs->flavor = (u32)(-1);
else
/* Is this legal? Be generous, take it to mean AUTH_NONE: */
cbs->flavor = 0;
for (i = 0; i < nr_secflavs; ++i) {
READ_BUF(4);
dummy = be32_to_cpup(p++);
switch (dummy) {
if (xdr_stream_decode_u32(argp->xdr, &secflavor) < 0)
return nfserr_bad_xdr;
switch (secflavor) {
case RPC_AUTH_NULL:
/* Nothing to read */
/* void */
if (cbs->flavor == (u32)(-1))
cbs->flavor = RPC_AUTH_NULL;
break;
case RPC_AUTH_UNIX:
READ_BUF(8);
/* stamp */
dummy = be32_to_cpup(p++);
/* machine name */
dummy = be32_to_cpup(p++);
READ_BUF(dummy);
SAVEMEM(machine_name, dummy);
/* uid, gid */
READ_BUF(8);
uid = be32_to_cpup(p++);
gid = be32_to_cpup(p++);
/* more gids */
READ_BUF(4);
dummy = be32_to_cpup(p++);
READ_BUF(dummy * 4);
if (cbs->flavor == (u32)(-1)) {
kuid_t kuid = make_kuid(userns, uid);
kgid_t kgid = make_kgid(userns, gid);
if (uid_valid(kuid) && gid_valid(kgid)) {
cbs->uid = kuid;
cbs->gid = kgid;
cbs->flavor = RPC_AUTH_UNIX;
} else {
dprintk("RPC_AUTH_UNIX with invalid"
"uid or gid ignoring!\n");
}
}
status = nfsd4_decode_authsys_parms(argp, cbs);
if (status)
return status;
break;
case RPC_AUTH_GSS:
dprintk("RPC_AUTH_GSS callback secflavor "
"not supported!\n");
READ_BUF(8);
/* gcbp_service */
dummy = be32_to_cpup(p++);
/* gcbp_handle_from_server */
dummy = be32_to_cpup(p++);
READ_BUF(dummy);
p += XDR_QUADLEN(dummy);
/* gcbp_handle_from_client */
READ_BUF(4);
dummy = be32_to_cpup(p++);
READ_BUF(dummy);
status = nfsd4_decode_gss_cb_handles4(argp, cbs);
if (status)
return status;
break;
default:
dprintk("Illegal callback secflavor\n");
return nfserr_inval;
}
}
DECODE_TAIL;
return nfs_ok;
}
/*
* NFSv4 operation argument decoders
*/