fs/fuse/dev.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
The operations FUSE_NOTIFY_STORE and FUSE_NOTIFY_RETRIEVE allow the
FUSE daemon to actively write/read pagecache contents.
For directories with FOPEN_CACHE_DIR, the pagecache is used as
kernel-internal cache storage, and userspace is not supposed to have
direct access to this cache - in particular, fuse_parse_cache() will hit
WARN_ON() if the cache contains bogus data.
Reject FUSE_NOTIFY_STORE and FUSE_NOTIFY_RETRIEVE on directories with
-EINVAL.
Fixes: 5d7bc7e8680c ("fuse: allow using readdir cache")
Cc: stable@vger.kernel.org
Signed-off-by: Jann Horn <jannh@google.com>
---
fs/fuse/dev.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 5dda7080f4a9..7096f53d335c 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1793,6 +1793,10 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
inode = fuse_ilookup(fc, nodeid, NULL);
if (!inode)
goto out_up_killsb;
+ if (S_ISDIR(inode->i_mode)) {
+ err = -EINVAL;
+ goto out_iput;
+ }
mapping = inode->i_mapping;
file_size = i_size_read(inode);
@@ -1966,7 +1970,10 @@ static int fuse_notify_retrieve(struct fuse_conn *fc, unsigned int size,
inode = fuse_ilookup(fc, nodeid, &fm);
if (inode) {
- err = fuse_retrieve(fm, inode, &outarg);
+ if (S_ISDIR(inode->i_mode))
+ err = -EINVAL;
+ else
+ err = fuse_retrieve(fm, inode, &outarg);
iput(inode);
}
up_read(&fc->killsb);
---
base-commit: ab5fce87a778cb780a05984a2ca448f2b41aafbf
change-id: 20260519-fuse-dir-pagecache-382a54146826
--
Jann Horn <jannh@google.com>
On Tue, 19 May 2026 at 16:00, Jann Horn <jannh@google.com> wrote: > > The operations FUSE_NOTIFY_STORE and FUSE_NOTIFY_RETRIEVE allow the > FUSE daemon to actively write/read pagecache contents. > > For directories with FOPEN_CACHE_DIR, the pagecache is used as > kernel-internal cache storage, and userspace is not supposed to have > direct access to this cache - in particular, fuse_parse_cache() will hit > WARN_ON() if the cache contains bogus data. > > Reject FUSE_NOTIFY_STORE and FUSE_NOTIFY_RETRIEVE on directories with > -EINVAL. Good catch. Shouldn't this reject !S_ISREG()? Symlinks also use the page cache and could break if overwritten by arbitrary data. Thanks, Miklos
On Tue, May 19, 2026 at 4:07 PM Miklos Szeredi <miklos@szeredi.hu> wrote: > On Tue, 19 May 2026 at 16:00, Jann Horn <jannh@google.com> wrote: > > The operations FUSE_NOTIFY_STORE and FUSE_NOTIFY_RETRIEVE allow the > > FUSE daemon to actively write/read pagecache contents. > > > > For directories with FOPEN_CACHE_DIR, the pagecache is used as > > kernel-internal cache storage, and userspace is not supposed to have > > direct access to this cache - in particular, fuse_parse_cache() will hit > > WARN_ON() if the cache contains bogus data. > > > > Reject FUSE_NOTIFY_STORE and FUSE_NOTIFY_RETRIEVE on directories with > > -EINVAL. > > Good catch. > > Shouldn't this reject !S_ISREG()? Symlinks also use the page cache > and could break if overwritten by arbitrary data. Should it be `!(S_ISREG() || S_ISBLK())` ? I think block devices are supposed to act roughly like regular files in terms of pagecache, but IDK how that works in the context of FUSE. Let me know which way you prefer and I'll send a v2.
On Tue, 19 May 2026 at 16:12, Jann Horn <jannh@google.com> wrote: > Should it be `!(S_ISREG() || S_ISBLK())` ? > I think block devices are supposed to act roughly like regular files > in terms of pagecache, but IDK how that works in the context of FUSE. > Let me know which way you prefer and I'll send a v2. Handling I/O on block devices (or any special files for that matter) is completely out of fuse's control. So definitely shouldn't allow manipulating the cache for those, though I don't think it would actually do that since in the case of block devices the page cache resides in struct block_device, not on the fs's device node. Thanks, Miklos
© 2016 - 2026 Red Hat, Inc.