diff options
author | Nick Piggin <npiggin@suse.de> | 2007-02-20 16:58:08 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-20 20:10:15 -0500 |
commit | 955eff5acc8b8cd1c7d4eec0229c35eaabe013db (patch) | |
tree | 08d61e41bc12f3d1d9160e39ae6b45df6b9687d9 /fs/libfs.c | |
parent | c066332fb15adde1f37d874a67a1f9f7e4206484 (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>
Diffstat (limited to 'fs/libfs.c')
-rw-r--r-- | fs/libfs.c | 5 |
1 files changed, 3 insertions, 2 deletions
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 | ||
343 | int simple_commit_write(struct file *file, struct page *page, | 342 | int 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. |