Commit:     955eff5acc8b8cd1c7d4eec0229c35eaabe013db
Parent:     c066332fb15adde1f37d874a67a1f9f7e4206484
Author:     Nick Piggin <[EMAIL PROTECTED]>
AuthorDate: Tue Feb 20 13:58:08 2007 -0800
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Tue Feb 20 17:10:15 2007 -0800

    [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 <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
 Documentation/filesystems/vfs.txt |    5 +++++
 fs/libfs.c                        |    5 +++--
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/Documentation/filesystems/vfs.txt 
index 7737bfd..ea271f2 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -617,6 +617,11 @@ struct address_space_operations {
        In this case the prepare_write will be retried one the lock is
+       Note: the page _must not_ be marked uptodate in this function
+       (or anywhere else) unless it actually is uptodate right now. As
+       soon as a page is marked uptodate, it is possible for a concurrent
+       read(2) to copy it to userspace.
   commit_write: If prepare_write succeeds, new data will be copied
         into the page and then commit_write will be called.  It will
         typically update the size of the file (if appropriate) and
diff --git a/fs/libfs.c b/fs/libfs.c
index 7d48704..cf79196 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -335,17 +335,18 @@ int simple_prepare_write(struct file *file, struct page 
                        kunmap_atomic(kaddr, KM_USER0);
-               SetPageUptodate(page);
        return 0;
 int simple_commit_write(struct file *file, struct page *page,
-                       unsigned offset, unsigned to)
+                       unsigned from, unsigned to)
        struct inode *inode = page->mapping->host;
        loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
+       if (!PageUptodate(page))
+               SetPageUptodate(page);
         * No need to use i_size_read() here, the i_size
         * cannot change under us because we hold the i_mutex.
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at

Reply via email to