summaryrefslogtreecommitdiff
path: root/fs/fuse
diff options
context:
space:
mode:
authorJann Horn <jannh@google.com>2024-08-06 21:51:42 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2024-08-18 08:45:39 -0700
commit3c0da3d163eb32f1f91891efaade027fa9b245b9 (patch)
tree044d7125e167dff4b438d662533ac955d6dd067d /fs/fuse
parentc3f2d783a459980eafd24c5af94ccd56a615961f (diff)
downloadlwn-3c0da3d163eb32f1f91891efaade027fa9b245b9.tar.gz
lwn-3c0da3d163eb32f1f91891efaade027fa9b245b9.zip
fuse: Initialize beyond-EOF page contents before setting uptodate
fuse_notify_store(), unlike fuse_do_readpage(), does not enable page zeroing (because it can be used to change partial page contents). So fuse_notify_store() must be more careful to fully initialize page contents (including parts of the page that are beyond end-of-file) before marking the page uptodate. The current code can leave beyond-EOF page contents uninitialized, which makes these uninitialized page contents visible to userspace via mmap(). This is an information leak, but only affects systems which do not enable init-on-alloc (via CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y or the corresponding kernel command line parameter). Link: https://bugs.chromium.org/p/project-zero/issues/detail?id=2574 Cc: stable@kernel.org Fixes: a1d75f258230 ("fuse: add store request") Signed-off-by: Jann Horn <jannh@google.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/fuse')
-rw-r--r--fs/fuse/dev.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 9eb191b5c4de..7146038b2fe7 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1618,9 +1618,11 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
this_num = min_t(unsigned, num, PAGE_SIZE - offset);
err = fuse_copy_page(cs, &page, offset, this_num, 0);
- if (!err && offset == 0 &&
- (this_num == PAGE_SIZE || file_size == end))
+ if (!PageUptodate(page) && !err && offset == 0 &&
+ (this_num == PAGE_SIZE || file_size == end)) {
+ zero_user_segment(page, this_num, PAGE_SIZE);
SetPageUptodate(page);
+ }
unlock_page(page);
put_page(page);