From fd7daa9d5d9273607bfd8ff01fb771229d8f97ee Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Fri, 11 Nov 2022 13:17:32 -0500 Subject: [PATCH] Fixes for 5.10 Signed-off-by: Sasha Levin --- queue-5.10/fuse-fix-readdir-cache-race.patch | 65 ++++++++++++++++++++ queue-5.10/series | 1 + 2 files changed, 66 insertions(+) create mode 100644 queue-5.10/fuse-fix-readdir-cache-race.patch diff --git a/queue-5.10/fuse-fix-readdir-cache-race.patch b/queue-5.10/fuse-fix-readdir-cache-race.patch new file mode 100644 index 00000000000..e10acc0b7b1 --- /dev/null +++ b/queue-5.10/fuse-fix-readdir-cache-race.patch @@ -0,0 +1,65 @@ +From 8c5066aea7ef112b37ccce2cc0521124c4442abb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Oct 2022 17:18:58 +0200 +Subject: fuse: fix readdir cache race + +From: Miklos Szeredi + +[ 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 +Fixes: 5d7bc7e8680c ("fuse: allow using readdir cache") +Cc: # v4.20 +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/readdir.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +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) { + /* +-- +2.35.1 + diff --git a/queue-5.10/series b/queue-5.10/series index e69de29bb2d..c3dfaf8a9c1 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -0,0 +1 @@ +fuse-fix-readdir-cache-race.patch -- 2.47.3