Patch "fuse: fix readdir cache race" has been added to the 5.10-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    fuse: fix readdir cache race

to the 5.10-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:
     fuse-fix-readdir-cache-race.patch
and it can be found in the queue-5.10 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 8c5066aea7ef112b37ccce2cc0521124c4442abb
Author: Miklos Szeredi <mszeredi@xxxxxxxxxx>
Date:   Thu Oct 20 17:18:58 2022 +0200

    fuse: fix readdir cache race
    
    [ Upstream commit 9fa248c65bdbf5af0a2f74dd38575acfc8dfd2bf ]
    
    There's a race in fuse's readdir cache that can result in an uninitilized
    page being read.  The page lock is supposed to prevent this from happening
    but in the following case it doesn't:
    
    Two fuse_add_dirent_to_cache() start out and get the same parameters
    (size=0,offset=0).  One of them wins the race to create and lock the page,
    after which it fills in data, sets rdc.size and unlocks the page.
    
    In the meantime the page gets evicted from the cache before the other
    instance gets to run.  That one also creates the page, but finds the
    size to be mismatched, bails out and leaves the uninitialized page in the
    cache.
    
    Fix by marking a filled page uptodate and ignoring non-uptodate pages.
    
    Reported-by: Frank Sorenson <fsorenso@xxxxxxxxxx>
    Fixes: 5d7bc7e8680c ("fuse: allow using readdir cache")
    Cc: <stable@xxxxxxxxxxxxxxx> # v4.20
    Signed-off-by: Miklos Szeredi <mszeredi@xxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c
index bc267832310c..d5294e663df5 100644
--- a/fs/fuse/readdir.c
+++ b/fs/fuse/readdir.c
@@ -77,8 +77,10 @@ static void fuse_add_dirent_to_cache(struct file *file,
 		goto unlock;
 
 	addr = kmap_atomic(page);
-	if (!offset)
+	if (!offset) {
 		clear_page(addr);
+		SetPageUptodate(page);
+	}
 	memcpy(addr + offset, dirent, reclen);
 	kunmap_atomic(addr);
 	fi->rdc.size = (index << PAGE_SHIFT) + offset + reclen;
@@ -516,6 +518,12 @@ static int fuse_readdir_cached(struct file *file, struct dir_context *ctx)
 
 	page = find_get_page_flags(file->f_mapping, index,
 				   FGP_ACCESSED | FGP_LOCK);
+	/* Page gone missing, then re-added to cache, but not initialized? */
+	if (page && !PageUptodate(page)) {
+		unlock_page(page);
+		put_page(page);
+		page = NULL;
+	}
 	spin_lock(&fi->rdc.lock);
 	if (!page) {
 		/*



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux