diff options
author | Michel Lespinasse <walken@google.com> | 2013-02-22 19:32:46 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-23 20:50:11 -0500 |
commit | 1869305009857cdeaabe6283bcdc2359c5784543 (patch) | |
tree | a8a500c71e7aa3a645322635f3d591c16601af27 /mm/fremap.c | |
parent | cea10a19b7972a1954c4a2d05a7de8db48b444fb (diff) |
mm: introduce VM_POPULATE flag to better deal with racy userspace programs
The vm_populate() code populates user mappings without constantly
holding the mmap_sem. This makes it susceptible to racy userspace
programs: the user mappings may change while vm_populate() is running,
and in this case vm_populate() may end up populating the new mapping
instead of the old one.
In order to reduce the possibility of userspace getting surprised by
this behavior, this change introduces the VM_POPULATE vma flag which
gets set on vmas we want vm_populate() to work on. This way
vm_populate() may still end up populating the new mapping after such a
race, but only if the new mapping is also one that the user has
requested (using MAP_SHARED, MAP_LOCKED or mlock) to be populated.
Signed-off-by: Michel Lespinasse <walken@google.com>
Acked-by: Rik van Riel <riel@redhat.com>
Tested-by: Andy Lutomirski <luto@amacapital.net>
Cc: Greg Ungerer <gregungerer@westnet.com.au>
Cc: David Howells <dhowells@redhat.com>
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 | 12 |
1 files changed, 10 insertions, 2 deletions
diff --git a/mm/fremap.c b/mm/fremap.c index 503a72387087..0cd4c11488ed 100644 --- a/mm/fremap.c +++ b/mm/fremap.c | |||
@@ -204,8 +204,10 @@ get_write_lock: | |||
204 | unsigned long addr; | 204 | unsigned long addr; |
205 | struct file *file = get_file(vma->vm_file); | 205 | struct file *file = get_file(vma->vm_file); |
206 | 206 | ||
207 | addr = mmap_region(file, start, size, | 207 | vm_flags = vma->vm_flags; |
208 | vma->vm_flags, pgoff); | 208 | if (!(flags & MAP_NONBLOCK)) |
209 | vm_flags |= VM_POPULATE; | ||
210 | addr = mmap_region(file, start, size, vm_flags, pgoff); | ||
209 | fput(file); | 211 | fput(file); |
210 | if (IS_ERR_VALUE(addr)) { | 212 | if (IS_ERR_VALUE(addr)) { |
211 | err = addr; | 213 | err = addr; |
@@ -224,6 +226,12 @@ get_write_lock: | |||
224 | mutex_unlock(&mapping->i_mmap_mutex); | 226 | mutex_unlock(&mapping->i_mmap_mutex); |
225 | } | 227 | } |
226 | 228 | ||
229 | if (!(flags & MAP_NONBLOCK) && !(vma->vm_flags & VM_POPULATE)) { | ||
230 | if (!has_write_lock) | ||
231 | goto get_write_lock; | ||
232 | vma->vm_flags |= VM_POPULATE; | ||
233 | } | ||
234 | |||
227 | if (vma->vm_flags & VM_LOCKED) { | 235 | if (vma->vm_flags & VM_LOCKED) { |
228 | /* | 236 | /* |
229 | * drop PG_Mlocked flag for over-mapped range | 237 | * drop PG_Mlocked flag for over-mapped range |