summaryrefslogtreecommitdiff
path: root/fs/fuse
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2025-02-20 11:02:58 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-03-22 12:50:44 -0700
commitfcfb7ea1f4c62323fb1fe8a893c96a957ba19bea (patch)
treeac80b6529cd60a1f82d40f0da40ebeb7563de4d0 /fs/fuse
parent08ee4f873bd0029a5eed293af31ffcf5a23f9fa8 (diff)
downloadlinux-fcfb7ea1f4c62323fb1fe8a893c96a957ba19bea.tar.gz
linux-fcfb7ea1f4c62323fb1fe8a893c96a957ba19bea.tar.bz2
linux-fcfb7ea1f4c62323fb1fe8a893c96a957ba19bea.zip
fuse: don't truncate cached, mutated symlink
[ Upstream commit b4c173dfbb6c78568578ff18f9e8822d7bd0e31b ] Fuse allows the value of a symlink to change and this property is exploited by some filesystems (e.g. CVMFS). It has been observed, that sometimes after changing the symlink contents, the value is truncated to the old size. This is caused by fuse_getattr() racing with fuse_reverse_inval_inode(). fuse_reverse_inval_inode() updates the fuse_inode's attr_version, which results in fuse_change_attributes() exiting before updating the cached attributes This is okay, as the cached attributes remain invalid and the next call to fuse_change_attributes() will likely update the inode with the correct values. The reason this causes problems is that cached symlinks will be returned through page_get_link(), which truncates the symlink to inode->i_size. This is correct for filesystems that don't mutate symlinks, but in this case it causes bad behavior. The solution is to just remove this truncation. This can cause a regression in a filesystem that relies on supplying a symlink larger than the file size, but this is unlikely. If that happens we'd need to make this behavior conditional. Reported-by: Laura Promberger <laura.promberger@cern.ch> Tested-by: Sam Lewis <samclewis@google.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Link: https://lore.kernel.org/r/20250220100258.793363-1-mszeredi@redhat.com Reviewed-by: Bernd Schubert <bschubert@ddn.com> Signed-off-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'fs/fuse')
-rw-r--r--fs/fuse/dir.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 95f9913a3537..89bffaed421f 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1608,7 +1608,7 @@ static const char *fuse_get_link(struct dentry *dentry, struct inode *inode,
goto out_err;
if (fc->cache_symlinks)
- return page_get_link(dentry, inode, callback);
+ return page_get_link_raw(dentry, inode, callback);
err = -ECHILD;
if (!dentry)