diff options
author | Rik van Riel <riel@redhat.com> | 2014-01-02 15:58:46 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-02 17:40:30 -0500 |
commit | 4eb919825e6c3c7fb3630d5621f6d11e98a18b3a (patch) | |
tree | 826d9e3d7852f7d2214a31bcca050bcd5573e667 /mm/fremap.c | |
parent | 3b25df93c6e37e323b86a2a8c1e00c0a2821c6c9 (diff) |
mm: fix use-after-free in sys_remap_file_pages
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>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/fremap.c')
-rw-r--r-- | mm/fremap.c | 8 |
1 files changed, 5 insertions, 3 deletions
diff --git a/mm/fremap.c b/mm/fremap.c index 5bff08147768..bbc4d660221a 100644 --- a/mm/fremap.c +++ b/mm/fremap.c | |||
@@ -208,9 +208,10 @@ get_write_lock: | |||
208 | if (mapping_cap_account_dirty(mapping)) { | 208 | if (mapping_cap_account_dirty(mapping)) { |
209 | unsigned long addr; | 209 | unsigned long addr; |
210 | struct file *file = get_file(vma->vm_file); | 210 | struct file *file = get_file(vma->vm_file); |
211 | /* mmap_region may free vma; grab the info now */ | ||
212 | vm_flags = vma->vm_flags; | ||
211 | 213 | ||
212 | addr = mmap_region(file, start, size, | 214 | addr = mmap_region(file, start, size, vm_flags, pgoff); |
213 | vma->vm_flags, pgoff); | ||
214 | fput(file); | 215 | fput(file); |
215 | if (IS_ERR_VALUE(addr)) { | 216 | if (IS_ERR_VALUE(addr)) { |
216 | err = addr; | 217 | err = addr; |
@@ -218,7 +219,7 @@ get_write_lock: | |||
218 | BUG_ON(addr != start); | 219 | BUG_ON(addr != start); |
219 | err = 0; | 220 | err = 0; |
220 | } | 221 | } |
221 | goto out; | 222 | goto out_freed; |
222 | } | 223 | } |
223 | mutex_lock(&mapping->i_mmap_mutex); | 224 | mutex_lock(&mapping->i_mmap_mutex); |
224 | flush_dcache_mmap_lock(mapping); | 225 | flush_dcache_mmap_lock(mapping); |
@@ -253,6 +254,7 @@ get_write_lock: | |||
253 | out: | 254 | out: |
254 | if (vma) | 255 | if (vma) |
255 | vm_flags = vma->vm_flags; | 256 | vm_flags = vma->vm_flags; |
257 | out_freed: | ||
256 | if (likely(!has_write_lock)) | 258 | if (likely(!has_write_lock)) |
257 | up_read(&mm->mmap_sem); | 259 | up_read(&mm->mmap_sem); |
258 | else | 260 | else |