Loading fs/nfsd/nfs4xdr.c +107 −58 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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; 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); u32 dummy, uid, gid; char *machine_name; int i; int nr_secflavs; 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 */ Loading Loading
fs/nfsd/nfs4xdr.c +107 −58 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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; 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); u32 dummy, uid, gid; char *machine_name; int i; int nr_secflavs; 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 */ Loading