[PATCH] NFS: fix folio dereference before NULL check in nfs_inode_remove_request()

Jiangshan Yi <yijiangshan-UOlijcLmZ/[email protected]>
Newsgroups gmane.linux.nfs,gmane.linux.kernel
Message-ID <[email protected]>
nfs_inode_remove_request() obtains the folio for the head request via
nfs_page_to_folio(), which returns NULL when the PG_FOLIO flag is not
set on req->wb_head.

The presence of the "if (likely(folio))" check shows the code already
assumes folio can be NULL. However, folio was dereferenced before that
check:

        folio = nfs_page_to_folio(req->wb_head);
        mapping = folio->mapping;                       /* deref */

        spin_lock(&mapping->i_private_lock);
        if (likely(folio)) {                            /* too late */

folio->mapping is read (and mapping->i_private_lock is taken, and
folio_end_dropbehind(folio) is called outside the check) before folio
is validated, so a NULL folio would crash before the guard is ever
reached, rendering the check useless.

Move the folio->mapping read, the i_private_lock section and the
folio_end_dropbehind() call inside the "if (likely(folio))" block so
the folio is only dereferenced after it has been confirmed non-NULL.
The behaviour is unchanged when folio is non-NULL.

Signed-off-by: Jiangshan Yi <yijiangshan-UOlijcLmZ/[email protected]>
---
 fs/nfs/write.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index fcffb8c9e9df..33d51eb9a3a4 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -739,17 +739,18 @@ static void nfs_inode_remove_request(struct nfs_page *req)
 	nfs_page_group_lock(req);
 	if (nfs_page_group_sync_on_bit_locked(req, PG_REMOVE)) {
 		struct folio *folio = nfs_page_to_folio(req->wb_head);
-		struct address_space *mapping = folio->mapping;
 
-		spin_lock(&mapping->i_private_lock);
 		if (likely(folio)) {
+			struct address_space *mapping = folio->mapping;
+
+			spin_lock(&mapping->i_private_lock);
 			folio->private = NULL;
 			folio_clear_private(folio);
 			clear_bit(PG_MAPPED, &req->wb_head->wb_flags);
-		}
-		spin_unlock(&mapping->i_private_lock);
+			spin_unlock(&mapping->i_private_lock);
 
-		folio_end_dropbehind(folio);
+			folio_end_dropbehind(folio);
+		}
 	}
 	nfs_page_group_unlock(req);
 
-- 
2.25.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.