NFSD: Replace READ* macros in nfsd4_decode_cb_sec()
authorChuck Lever <chuck.lever@oracle.com>
Tue, 3 Nov 2020 18:09:34 +0000 (13:09 -0500)
committerChuck Lever <chuck.lever@oracle.com>
Mon, 30 Nov 2020 19:46:40 +0000 (14:46 -0500)
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfsd/nfs4xdr.c

index 667f6d9..61f9186 100644 (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
  */