From patchwork Tue May 17 05:46:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frank Heimes X-Patchwork-Id: 1632042 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=canonical.com header.i=@canonical.com header.a=rsa-sha256 header.s=20210705 header.b=a2R2i/4V; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4L2Q9x3vS2z9s0r for ; Tue, 17 May 2022 15:47:17 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1nqq36-00012a-FA; Tue, 17 May 2022 05:47:12 +0000 Received: from smtp-relay-canonical-1.internal ([10.131.114.174] helo=smtp-relay-canonical-1.canonical.com) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1nqq34-00011s-2c for kernel-team@lists.ubuntu.com; Tue, 17 May 2022 05:47:10 +0000 Received: from T570.fritz.box (2.general.fheimes.us.vpn [10.172.66.67]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-canonical-1.canonical.com (Postfix) with ESMTPSA id EA4CF3F741 for ; Tue, 17 May 2022 05:47:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1652766428; bh=XAyO5ILQiZS0IzhBiE67F4Rj4uJ7G6Z9T85OQoDa4BI=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=a2R2i/4VM0qfuvDE2QOSlLY0t6XspK9Wza3xoA2BowqbV/+rGjfIJoEmZ7U7rF2TS ++THifkB52/D/FsPsG3LkSevEIL44ZsxeCDbx0I9FAd8eilMxciWHhYF2h1LIblFSm 1qwSXl7YiWVQlvM0LaqPXkH1LGIit3QLKW9Zn93fnzFAKnOwYr2Z727/XL5XVB5NB8 7s1fZ+hVeqWsR3mM/WO88nQMbRa+aTJw+xvHXS893oUcT/juimd5I+m/ovLaoUwFxk 5yABxskK82URaE+KkZoqZlDCOgGviZGBux0sSk+QT7aCUrQNu/5rxVRLEb4kyCWmA2 B/a391lXOWb7Q== From: frank.heimes@canonical.com To: kernel-team@lists.ubuntu.com Subject: [SRU][J][I][F][PATCH 1/1] NFS: Fix up nfs_ctx_key_to_expire() Date: Tue, 17 May 2022 07:46:00 +0200 Message-Id: <20220517054600.286384-2-frank.heimes@canonical.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220517054600.286384-1-frank.heimes@canonical.com> References: <20220517054600.286384-1-frank.heimes@canonical.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Trond Myklebust BugLink: https://bugs.launchpad.net/bugs/1968096 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: Trond Myklebust (cherry picked from commit ca05cbae2a0468e5d78e9b4605936a8bf5da328b) Signed-off-by: Frank Heimes --- fs/nfs/inode.c | 4 ++-- fs/nfs/write.c | 41 ++++++++++++++++++++++++++++------------- include/linux/nfs_fs.h | 2 +- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index f4f75db7a825..ee99bad240e6 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1026,7 +1026,7 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, ctx->cred = get_cred(filp->f_cred); else ctx->cred = get_current_cred(); - ctx->ll_cred = NULL; + rcu_assign_pointer(ctx->ll_cred, NULL); ctx->state = NULL; ctx->mode = f_mode; ctx->flags = 0; @@ -1065,7 +1065,7 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync) put_cred(ctx->cred); dput(ctx->dentry); nfs_sb_deactive(sb); - put_rpccred(ctx->ll_cred); + put_rpccred(rcu_dereference_protected(ctx->ll_cred, 1)); kfree(ctx->mdsthreshold); kfree_rcu(ctx, rcu_head); } diff --git a/fs/nfs/write.c b/fs/nfs/write.c index d21b25511499..1f7e1ebfb622 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1231,7 +1231,7 @@ nfs_key_timeout_notify(struct file *filp, struct inode *inode) struct nfs_open_context *ctx = nfs_file_open_context(filp); if (nfs_ctx_key_to_expire(ctx, inode) && - !ctx->ll_cred) + !rcu_access_pointer(ctx->ll_cred)) /* Already expired! */ return -EACCES; return 0; @@ -1243,23 +1243,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) { 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 = { .cred = ctx->cred, }; + bool ret = false; - if (cred && !cred->cr_ops->crmatch(&acred, cred, 0)) { - put_rpccred(cred); - ctx->ll_cred = NULL; - cred = NULL; - } - if (!cred) - cred = auth->au_ops->lookup_cred(auth, &acred, 0); - if (!cred || IS_ERR(cred)) + rcu_read_lock(); + cred = rcu_dereference(ctx->ll_cred); + if (cred && !(cred->cr_ops->crkey_timeout && + cred->cr_ops->crkey_timeout(cred))) + goto out; + rcu_read_unlock(); + + new = auth->au_ops->lookup_cred(auth, &acred, 0); + if (new == cred) { + put_rpccred(new); return true; - ctx->ll_cred = cred; - return !!(cred->cr_ops->crkey_timeout && - cred->cr_ops->crkey_timeout(cred)); + } + if (IS_ERR_OR_NULL(new)) { + 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; } /* diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 5ffcde9ac413..af8fe97474bc 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -81,7 +81,7 @@ struct nfs_open_context { fl_owner_t flock_owner; struct dentry *dentry; 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; fmode_t mode;