Patch "netfs: Fix potential UAF in netfs_unlock_abandoned_read_pages()" has been added to the 6.12-stable tree

<[email protected]>
Newsgroups dev.linux.lists.netfs
Message-ID <2026082421-agility-reusable-88f1@gregkh>
This is a note to let you know that I've just added the patch titled

    netfs: Fix potential UAF in netfs_unlock_abandoned_read_pages()

to the 6.12-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     netfs-fix-potential-uaf-in-netfs_unlock_abandoned_read_pages.patch
and it can be found in the queue-6.12 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <[email protected]> know about it.


From dbe556972100fabb8e5a1b3d2163831ff07b1e8e Mon Sep 17 00:00:00 2001
From: David Howells <[email protected]>
Date: Tue, 12 May 2026 13:33:56 +0100
Subject: netfs: Fix potential UAF in netfs_unlock_abandoned_read_pages()

From: David Howells <[email protected]>

commit dbe556972100fabb8e5a1b3d2163831ff07b1e8e upstream.

netfs_unlock_abandoned_read_pages(rreq) accesses the index of the folios it
is wanting to unlock and compares that to rreq->no_unlock_folio so that it
doesn't unlock a folio being read for netfs_perform_write() or
netfs_write_begin().

However, given that netfs_unlock_abandoned_read_pages() is called _after_
NETFS_RREQ_IN_PROGRESS is cleared, the one folio that it's not allowed to
dereference is the one specified by ->no_unlock_folio as ownership
immediately reverts to the caller.

Fix this by storing the folio pointer instead and using that rather than
the index.  Also fix netfs_unlock_read_folio() where the same applies.

Fixes: ee4cdf7ba857 ("netfs: Speed up buffered reading")
Closes: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com
Signed-off-by: David Howells <[email protected]>
Link: https://patch.msgid.link/[email protected]
cc: Paulo Alcantara <[email protected]>
cc: Viacheslav Dubeyko <[email protected]>
cc: Matthew Wilcox <[email protected]>
cc: [email protected]
cc: [email protected]
Signed-off-by: Christian Brauner <[email protected]>
Signed-off-by: Shishkin Aleksey <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
 fs/netfs/buffered_read.c |    4 ++--
 fs/netfs/read_collect.c  |    2 +-
 fs/netfs/read_retry.c    |    2 +-
 include/linux/netfs.h    |    2 +-
 4 files changed, 5 insertions(+), 5 deletions(-)

--- a/fs/netfs/buffered_read.c
+++ b/fs/netfs/buffered_read.c
@@ -734,7 +734,7 @@ retry:
 		ret = PTR_ERR(rreq);
 		goto error;
 	}
-	rreq->no_unlock_folio	= folio->index;
+	rreq->no_unlock_folio	= folio;
 	__set_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags);
 
 	ret = netfs_begin_cache_read(rreq, ctx);
@@ -800,7 +800,7 @@ int netfs_prefetch_for_write(struct file
 		goto error;
 	}
 
-	rreq->no_unlock_folio = folio->index;
+	rreq->no_unlock_folio = folio;
 	__set_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags);
 	ret = netfs_begin_cache_read(rreq, ctx);
 	if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS)
--- a/fs/netfs/read_collect.c
+++ b/fs/netfs/read_collect.c
@@ -73,7 +73,7 @@ static void netfs_unlock_read_folio(stru
 	}
 
 	if (!test_bit(NETFS_RREQ_DONT_UNLOCK_FOLIOS, &rreq->flags)) {
-		if (folio->index == rreq->no_unlock_folio &&
+		if (folio == rreq->no_unlock_folio &&
 		    test_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags)) {
 			_debug("no unlock");
 		} else {
--- a/fs/netfs/read_retry.c
+++ b/fs/netfs/read_retry.c
@@ -249,7 +249,7 @@ void netfs_unlock_abandoned_read_pages(s
 			struct folio *folio = folioq_folio(p, slot);
 
 			if (folio && !folioq_is_marked2(p, slot)) {
-				if (folio->index == rreq->no_unlock_folio &&
+				if (folio == rreq->no_unlock_folio &&
 				    test_bit(NETFS_RREQ_NO_UNLOCK_FOLIO,
 					     &rreq->flags)) {
 					_debug("no unlock");
--- a/include/linux/netfs.h
+++ b/include/linux/netfs.h
@@ -266,7 +266,7 @@ struct netfs_io_request {
 	atomic64_t		issued_to;	/* Write issuer folio cursor */
 	unsigned long long	collected_to;	/* Point we've collected to */
 	unsigned long long	cleaned_to;	/* Position we've cleaned folios to */
-	pgoff_t			no_unlock_folio; /* Don't unlock this folio after read */
+	const struct folio	*no_unlock_folio; /* Don't unlock this folio after read */
 	size_t			prev_donated;	/* Fallback for subreq->prev_donated */
 	refcount_t		ref;
 	unsigned long		flags;


Patches currently in stable-queue which might be from [email protected] are

queue-6.12/netfs-fix-potential-uaf-in-netfs_unlock_abandoned_read_pages.patch
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.