mm: fix use-after-free in sys_remap_file_pages
authorRik van Riel <riel@redhat.com>
Thu, 2 Jan 2014 20:58:46 +0000 (12:58 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 9 Jan 2014 20:24:24 +0000 (12:24 -0800)
commit 4eb919825e6c3c7fb3630d5621f6d11e98a18b3a upstream.

remap_file_pages calls mmap_region, which may merge the VMA with other
existing VMAs, and free "vma".  This can lead to a use-after-free bug.
Avoid the bug by remembering vm_flags before calling mmap_region, and
not trying to dereference vma later.

Signed-off-by: Rik van Riel <riel@redhat.com>
Reported-by: Dmitry Vyukov <dvyukov@google.com>
Cc: PaX Team <pageexec@freemail.hu>
Cc: Kees Cook <keescook@chromium.org>
Cc: Michel Lespinasse <walken@google.com>
Cc: Cyrill Gorcunov <gorcunov@openvz.org>
Cc: Hugh Dickins <hughd@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
mm/fremap.c

index 87da359..1fb6bfe 100644 (file)
@@ -203,9 +203,10 @@ get_write_lock:
                if (mapping_cap_account_dirty(mapping)) {
                        unsigned long addr;
                        struct file *file = get_file(vma->vm_file);
+                       /* mmap_region may free vma; grab the info now */
+                       vm_flags = vma->vm_flags;
 
-                       addr = mmap_region(file, start, size,
-                                       vma->vm_flags, pgoff);
+                       addr = mmap_region(file, start, size, vm_flags, pgoff);
                        fput(file);
                        if (IS_ERR_VALUE(addr)) {
                                err = addr;
@@ -213,7 +214,7 @@ get_write_lock:
                                BUG_ON(addr != start);
                                err = 0;
                        }
-                       goto out;
+                       goto out_freed;
                }
                mutex_lock(&mapping->i_mmap_mutex);
                flush_dcache_mmap_lock(mapping);
@@ -248,6 +249,7 @@ get_write_lock:
 out:
        if (vma)
                vm_flags = vma->vm_flags;
+out_freed:
        if (likely(!has_write_lock))
                up_read(&mm->mmap_sem);
        else