Commit ca05cbae authored by Trond Myklebust's avatar Trond Myklebust

NFS: Fix up nfs_ctx_key_to_expire()

If the cached credential exists but doesn't have any expiration callback
then exit early.
Fix up atomicity issues when replacing the credential with a new one
since the existing code could lead to refcount leaks.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent 9019fb39
...@@ -1024,7 +1024,7 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, ...@@ -1024,7 +1024,7 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry,
ctx->cred = get_cred(filp->f_cred); ctx->cred = get_cred(filp->f_cred);
else else
ctx->cred = get_current_cred(); ctx->cred = get_current_cred();
ctx->ll_cred = NULL; rcu_assign_pointer(ctx->ll_cred, NULL);
ctx->state = NULL; ctx->state = NULL;
ctx->mode = f_mode; ctx->mode = f_mode;
ctx->flags = 0; ctx->flags = 0;
...@@ -1063,7 +1063,7 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync) ...@@ -1063,7 +1063,7 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)
put_cred(ctx->cred); put_cred(ctx->cred);
dput(ctx->dentry); dput(ctx->dentry);
nfs_sb_deactive(sb); nfs_sb_deactive(sb);
put_rpccred(ctx->ll_cred); put_rpccred(rcu_dereference_protected(ctx->ll_cred, 1));
kfree(ctx->mdsthreshold); kfree(ctx->mdsthreshold);
kfree_rcu(ctx, rcu_head); kfree_rcu(ctx, rcu_head);
} }
......
...@@ -1246,7 +1246,7 @@ nfs_key_timeout_notify(struct file *filp, struct inode *inode) ...@@ -1246,7 +1246,7 @@ nfs_key_timeout_notify(struct file *filp, struct inode *inode)
struct nfs_open_context *ctx = nfs_file_open_context(filp); struct nfs_open_context *ctx = nfs_file_open_context(filp);
if (nfs_ctx_key_to_expire(ctx, inode) && if (nfs_ctx_key_to_expire(ctx, inode) &&
!ctx->ll_cred) !rcu_access_pointer(ctx->ll_cred))
/* Already expired! */ /* Already expired! */
return -EACCES; return -EACCES;
return 0; return 0;
...@@ -1258,23 +1258,38 @@ nfs_key_timeout_notify(struct file *filp, struct inode *inode) ...@@ -1258,23 +1258,38 @@ nfs_key_timeout_notify(struct file *filp, struct inode *inode)
bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx, struct inode *inode) bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx, struct inode *inode)
{ {
struct rpc_auth *auth = NFS_SERVER(inode)->client->cl_auth; struct rpc_auth *auth = NFS_SERVER(inode)->client->cl_auth;
struct rpc_cred *cred = ctx->ll_cred; struct rpc_cred *cred, *new, *old = NULL;
struct auth_cred acred = { struct auth_cred acred = {
.cred = ctx->cred, .cred = ctx->cred,
}; };
bool ret = false;
if (cred && !cred->cr_ops->crmatch(&acred, cred, 0)) { rcu_read_lock();
put_rpccred(cred); cred = rcu_dereference(ctx->ll_cred);
ctx->ll_cred = NULL; if (cred && !(cred->cr_ops->crkey_timeout &&
cred = NULL; cred->cr_ops->crkey_timeout(cred)))
} goto out;
if (!cred) rcu_read_unlock();
cred = auth->au_ops->lookup_cred(auth, &acred, 0);
if (!cred || IS_ERR(cred)) new = auth->au_ops->lookup_cred(auth, &acred, 0);
if (new == cred) {
put_rpccred(new);
return true; return true;
ctx->ll_cred = cred; }
return !!(cred->cr_ops->crkey_timeout && if (IS_ERR_OR_NULL(new)) {
cred->cr_ops->crkey_timeout(cred)); new = NULL;
ret = true;
} else if (new->cr_ops->crkey_timeout &&
new->cr_ops->crkey_timeout(new))
ret = true;
rcu_read_lock();
old = rcu_dereference_protected(xchg(&ctx->ll_cred,
RCU_INITIALIZER(new)), 1);
out:
rcu_read_unlock();
put_rpccred(old);
return ret;
} }
/* /*
......
...@@ -81,7 +81,7 @@ struct nfs_open_context { ...@@ -81,7 +81,7 @@ struct nfs_open_context {
fl_owner_t flock_owner; fl_owner_t flock_owner;
struct dentry *dentry; struct dentry *dentry;
const struct cred *cred; const struct cred *cred;
struct rpc_cred *ll_cred; /* low-level cred - use to check for expiry */ struct rpc_cred __rcu *ll_cred; /* low-level cred - use to check for expiry */
struct nfs4_state *state; struct nfs4_state *state;
fmode_t mode; fmode_t mode;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment