Skip to content

Commit d3b71f2

Browse files
author
CKI KWF Bot
committed
Merge: CVE-2025-39697: NFS: Fix a race when updating an existing write
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-10/-/merge_requests/1422 JIRA: https://issues.redhat.com/browse/RHEL-113858 CVE: CVE-2025-39697 ``` commit 76d2e38 Author: Trond Myklebust <trond.myklebust@hammerspace.com> Date: Sat Aug 16 07:25:20 2025 -0700 NFS: Fix a race when updating an existing write After nfs_lock_and_join_requests() tests for whether the request is still attached to the mapping, nothing prevents a call to nfs_inode_remove_request() from succeeding until we actually lock the page group. The reason is that whoever called nfs_inode_remove_request() doesn't necessarily have a lock on the page group head. So in order to avoid races, let's take the page group lock earlier in nfs_lock_and_join_requests(), and hold it across the removal of the request in nfs_inode_remove_request(). Reported-by: Jeff Layton <jlayton@kernel.org> Tested-by: Joe Quanaim <jdq@meta.com> Tested-by: Andrew Steffen <aksteffen@meta.com> Reviewed-by: Jeff Layton <jlayton@kernel.org> Fixes: bd37d6f ("NFSv4: Convert nfs_lock_and_join_requests() to use nfs_page_find_head_request()") Cc: stable@vger.kernel.org Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> ``` Signed-off-by: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com> --- <small>Created 2025-09-09 22:21 UTC by backporter - [KWF FAQ](https://red.ht/kernel_workflow_doc) - [Slack #team-kernel-workflow](https://redhat-internal.slack.com/archives/C04LRUPMJQ5) - [Source](https://gitlab.com/cki-project/kernel-workflow/-/blob/main/webhook/utils/backporter.py) - [Documentation](https://gitlab.com/cki-project/kernel-workflow/-/blob/main/docs/README.backporter.md) - [Report an issue](https://issues.redhat.com/secure/CreateIssueDetails!init.jspa?pid=12334433&issuetype=1&priority=4&summary=backporter+webhook+issue&components=kernel-workflow+/+backporter)</small> Approved-by: Jay Shin <jaeshin@redhat.com> Approved-by: Benjamin Coddington <bcodding@redhat.com> Approved-by: Scott Mayhew <smayhew@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
2 parents fdee88a + 2196cb4 commit d3b71f2

File tree

3 files changed

+16
-23
lines changed

3 files changed

+16
-23
lines changed

fs/nfs/pagelist.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,13 +253,14 @@ nfs_page_group_unlock(struct nfs_page *req)
253253
nfs_page_clear_headlock(req);
254254
}
255255

256-
/*
257-
* nfs_page_group_sync_on_bit_locked
256+
/**
257+
* nfs_page_group_sync_on_bit_locked - Test if all requests have @bit set
258+
* @req: request in page group
259+
* @bit: PG_* bit that is used to sync page group
258260
*
259261
* must be called with page group lock held
260262
*/
261-
static bool
262-
nfs_page_group_sync_on_bit_locked(struct nfs_page *req, unsigned int bit)
263+
bool nfs_page_group_sync_on_bit_locked(struct nfs_page *req, unsigned int bit)
263264
{
264265
struct nfs_page *head = req->wb_head;
265266
struct nfs_page *tmp;

fs/nfs/write.c

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -153,20 +153,10 @@ nfs_page_set_inode_ref(struct nfs_page *req, struct inode *inode)
153153
}
154154
}
155155

156-
static int
157-
nfs_cancel_remove_inode(struct nfs_page *req, struct inode *inode)
156+
static void nfs_cancel_remove_inode(struct nfs_page *req, struct inode *inode)
158157
{
159-
int ret;
160-
161-
if (!test_bit(PG_REMOVE, &req->wb_flags))
162-
return 0;
163-
ret = nfs_page_group_lock(req);
164-
if (ret)
165-
return ret;
166158
if (test_and_clear_bit(PG_REMOVE, &req->wb_flags))
167159
nfs_page_set_inode_ref(req, inode);
168-
nfs_page_group_unlock(req);
169-
return 0;
170160
}
171161

172162
/**
@@ -585,19 +575,18 @@ static struct nfs_page *nfs_lock_and_join_requests(struct folio *folio)
585575
}
586576
}
587577

578+
ret = nfs_page_group_lock(head);
579+
if (ret < 0)
580+
goto out_unlock;
581+
588582
/* Ensure that nobody removed the request before we locked it */
589583
if (head != folio->private) {
584+
nfs_page_group_unlock(head);
590585
nfs_unlock_and_release_request(head);
591586
goto retry;
592587
}
593588

594-
ret = nfs_cancel_remove_inode(head, inode);
595-
if (ret < 0)
596-
goto out_unlock;
597-
598-
ret = nfs_page_group_lock(head);
599-
if (ret < 0)
600-
goto out_unlock;
589+
nfs_cancel_remove_inode(head, inode);
601590

602591
/* lock each request in the page group */
603592
for (subreq = head->wb_this_page;
@@ -786,7 +775,8 @@ static void nfs_inode_remove_request(struct nfs_page *req)
786775
{
787776
struct nfs_inode *nfsi = NFS_I(nfs_page_to_inode(req));
788777

789-
if (nfs_page_group_sync_on_bit(req, PG_REMOVE)) {
778+
nfs_page_group_lock(req);
779+
if (nfs_page_group_sync_on_bit_locked(req, PG_REMOVE)) {
790780
struct folio *folio = nfs_page_to_folio(req->wb_head);
791781
struct address_space *mapping = folio->mapping;
792782

@@ -798,6 +788,7 @@ static void nfs_inode_remove_request(struct nfs_page *req)
798788
}
799789
spin_unlock(&mapping->i_private_lock);
800790
}
791+
nfs_page_group_unlock(req);
801792

802793
if (test_and_clear_bit(PG_INODE_REF, &req->wb_flags)) {
803794
atomic_long_dec(&nfsi->nrequests);

include/linux/nfs_page.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ extern void nfs_join_page_group(struct nfs_page *head,
160160
extern int nfs_page_group_lock(struct nfs_page *);
161161
extern void nfs_page_group_unlock(struct nfs_page *);
162162
extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int);
163+
extern bool nfs_page_group_sync_on_bit_locked(struct nfs_page *, unsigned int);
163164
extern int nfs_page_set_headlock(struct nfs_page *req);
164165
extern void nfs_page_clear_headlock(struct nfs_page *req);
165166
extern bool nfs_async_iocounter_wait(struct rpc_task *, struct nfs_lock_context *);

0 commit comments

Comments
 (0)