aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Piggin <npiggin@suse.de>2007-02-20 16:58:08 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-20 20:10:15 -0500
commit955eff5acc8b8cd1c7d4eec0229c35eaabe013db (patch)
tree08d61e41bc12f3d1d9160e39ae6b45df6b9687d9
parentc066332fb15adde1f37d874a67a1f9f7e4206484 (diff)
[PATCH] fs: fix libfs data leak
simple_prepare_write leaks uninitialised kernel data. This happens because the it leaves an uninitialised "hole" over the part of the page that the write is expected to go to. This is fine, but it then marks the page uptodate, which means a concurrent read can come in and copy the uninitialised memory into userspace before it written to. Fix it by simply marking it uptodate in simple_commit_write instead, after the hole has been filled in. This could theoretically break an fs that uses simple_prepare_write and not simple_commit_write, and that relies on the incorrect simple_prepare_write behaviour. Luckily, none of those exists in the tree. Signed-off-by: Nick Piggin <npiggin@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--Documentation/filesystems/vfs.txt5
-rw-r--r--fs/libfs.c5
2 files changed, 8 insertions, 2 deletions
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 7737bfd03cf8..ea271f2d3954 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -617,6 +617,11 @@ struct address_space_operations {
617 In this case the prepare_write will be retried one the lock is 617 In this case the prepare_write will be retried one the lock is
618 regained. 618 regained.
619 619
620 Note: the page _must not_ be marked uptodate in this function
621 (or anywhere else) unless it actually is uptodate right now. As
622 soon as a page is marked uptodate, it is possible for a concurrent
623 read(2) to copy it to userspace.
624
620 commit_write: If prepare_write succeeds, new data will be copied 625 commit_write: If prepare_write succeeds, new data will be copied
621 into the page and then commit_write will be called. It will 626 into the page and then commit_write will be called. It will
622 typically update the size of the file (if appropriate) and 627 typically update the size of the file (if appropriate) and
diff --git a/fs/libfs.c b/fs/libfs.c
index 7d487047dbb8..cf79196535ec 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -335,17 +335,18 @@ int simple_prepare_write(struct file *file, struct page *page,
335 flush_dcache_page(page); 335 flush_dcache_page(page);
336 kunmap_atomic(kaddr, KM_USER0); 336 kunmap_atomic(kaddr, KM_USER0);
337 } 337 }
338 SetPageUptodate(page);
339 } 338 }
340 return 0; 339 return 0;
341} 340}
342 341
343int simple_commit_write(struct file *file, struct page *page, 342int simple_commit_write(struct file *file, struct page *page,
344 unsigned offset, unsigned to) 343 unsigned from, unsigned to)
345{ 344{
346 struct inode *inode = page->mapping->host; 345 struct inode *inode = page->mapping->host;
347 loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; 346 loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
348 347
348 if (!PageUptodate(page))
349 SetPageUptodate(page);
349 /* 350 /*
350 * No need to use i_size_read() here, the i_size 351 * No need to use i_size_read() here, the i_size
351 * cannot change under us because we hold the i_mutex. 352 * cannot change under us because we hold the i_mutex.