aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4xdr.c
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2013-04-30 18:48:54 -0400
committerJ. Bruce Fields <bfields@redhat.com>2013-04-30 19:18:21 -0400
commit676e4ebd5f2c3b4fd1d2bff79b68385c23c5c105 (patch)
tree2e6af168ab04ed0c337c4faff795c60a6b6da472 /fs/nfsd/nfs4xdr.c
parented9411a00464860cafe7e07224818cdf04fd9e89 (diff)
NFSD: SECINFO doesn't handle unsupported pseudoflavors correctly
If nfsd4_do_encode_secinfo() can't find GSS info that matches an export security flavor, it assumes the flavor is not a GSS pseudoflavor, and simply puts it on the wire. However, if this XDR encoding logic is given a legitimate GSS pseudoflavor but the RPC layer says it does not support that pseudoflavor for some reason, then the server leaks GSS pseudoflavor numbers onto the wire. I confirmed this happens by blacklisting rpcsec_gss_krb5, then attempted a client transition from the pseudo-fs to a Kerberos-only share. The client received a flavor list containing the Kerberos pseudoflavor numbers, rather than GSS tuples. The encoder logic can check that each pseudoflavor in flavs[] is less than MAXFLAVOR before writing it into the buffer, to prevent this. But after "nflavs" is written into the XDR buffer, the encoder can't skip writing flavor information into the buffer when it discovers the RPC layer doesn't support that flavor. So count the number of valid flavors as they are written into the XDR buffer, then write that count into a placeholder in the XDR buffer when all recognized flavors have been encoded. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/nfs4xdr.c')
-rw-r--r--fs/nfsd/nfs4xdr.c26
1 files changed, 20 insertions, 6 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index a885e97dc5f4..6cd86e0fe450 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3085,10 +3085,11 @@ static __be32
3085nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp, 3085nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
3086 __be32 nfserr, struct svc_export *exp) 3086 __be32 nfserr, struct svc_export *exp)
3087{ 3087{
3088 u32 i, nflavs; 3088 u32 i, nflavs, supported;
3089 struct exp_flavor_info *flavs; 3089 struct exp_flavor_info *flavs;
3090 struct exp_flavor_info def_flavs[2]; 3090 struct exp_flavor_info def_flavs[2];
3091 __be32 *p; 3091 __be32 *p, *flavorsp;
3092 static bool report = true;
3092 3093
3093 if (nfserr) 3094 if (nfserr)
3094 goto out; 3095 goto out;
@@ -3112,13 +3113,17 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
3112 } 3113 }
3113 } 3114 }
3114 3115
3116 supported = 0;
3115 RESERVE_SPACE(4); 3117 RESERVE_SPACE(4);
3116 WRITE32(nflavs); 3118 flavorsp = p++; /* to be backfilled later */
3117 ADJUST_ARGS(); 3119 ADJUST_ARGS();
3120
3118 for (i = 0; i < nflavs; i++) { 3121 for (i = 0; i < nflavs; i++) {
3122 rpc_authflavor_t pf = flavs[i].pseudoflavor;
3119 struct rpcsec_gss_info info; 3123 struct rpcsec_gss_info info;
3120 3124
3121 if (rpcauth_get_gssinfo(flavs[i].pseudoflavor, &info) == 0) { 3125 if (rpcauth_get_gssinfo(pf, &info) == 0) {
3126 supported++;
3122 RESERVE_SPACE(4 + 4 + info.oid.len + 4 + 4); 3127 RESERVE_SPACE(4 + 4 + info.oid.len + 4 + 4);
3123 WRITE32(RPC_AUTH_GSS); 3128 WRITE32(RPC_AUTH_GSS);
3124 WRITE32(info.oid.len); 3129 WRITE32(info.oid.len);
@@ -3126,13 +3131,22 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
3126 WRITE32(info.qop); 3131 WRITE32(info.qop);
3127 WRITE32(info.service); 3132 WRITE32(info.service);
3128 ADJUST_ARGS(); 3133 ADJUST_ARGS();
3129 } else { 3134 } else if (pf < RPC_AUTH_MAXFLAVOR) {
3135 supported++;
3130 RESERVE_SPACE(4); 3136 RESERVE_SPACE(4);
3131 WRITE32(flavs[i].pseudoflavor); 3137 WRITE32(pf);
3132 ADJUST_ARGS(); 3138 ADJUST_ARGS();
3139 } else {
3140 if (report)
3141 pr_warn("NFS: SECINFO: security flavor %u "
3142 "is not supported\n", pf);
3133 } 3143 }
3134 } 3144 }
3135 3145
3146 if (nflavs != supported)
3147 report = false;
3148 *flavorsp = htonl(supported);
3149
3136out: 3150out:
3137 if (exp) 3151 if (exp)
3138 exp_put(exp); 3152 exp_put(exp);