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/mlock.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/mlock.c')
-rw-r--r-- | mm/mlock.c | 19 |
1 files changed, 10 insertions, 9 deletions
diff --git a/mm/mlock.c b/mm/mlock.c index 569400a5d079..d6378feb2950 100644 --- a/mm/mlock.c +++ b/mm/mlock.c | |||
@@ -340,9 +340,9 @@ static int do_mlock(unsigned long start, size_t len, int on) | |||
340 | 340 | ||
341 | /* Here we know that vma->vm_start <= nstart < vma->vm_end. */ | 341 | /* Here we know that vma->vm_start <= nstart < vma->vm_end. */ |
342 | 342 | ||
343 | newflags = vma->vm_flags | VM_LOCKED; | 343 | newflags = vma->vm_flags & ~VM_LOCKED; |
344 | if (!on) | 344 | if (on) |
345 | newflags &= ~VM_LOCKED; | 345 | newflags |= VM_LOCKED | VM_POPULATE; |
346 | 346 | ||
347 | tmp = vma->vm_end; | 347 | tmp = vma->vm_end; |
348 | if (tmp > end) | 348 | if (tmp > end) |
@@ -402,7 +402,8 @@ int __mm_populate(unsigned long start, unsigned long len, int ignore_errors) | |||
402 | * range with the first VMA. Also, skip undesirable VMA types. | 402 | * range with the first VMA. Also, skip undesirable VMA types. |
403 | */ | 403 | */ |
404 | nend = min(end, vma->vm_end); | 404 | nend = min(end, vma->vm_end); |
405 | if (vma->vm_flags & (VM_IO | VM_PFNMAP)) | 405 | if ((vma->vm_flags & (VM_IO | VM_PFNMAP | VM_POPULATE)) != |
406 | VM_POPULATE) | ||
406 | continue; | 407 | continue; |
407 | if (nstart < vma->vm_start) | 408 | if (nstart < vma->vm_start) |
408 | nstart = vma->vm_start; | 409 | nstart = vma->vm_start; |
@@ -475,18 +476,18 @@ static int do_mlockall(int flags) | |||
475 | struct vm_area_struct * vma, * prev = NULL; | 476 | struct vm_area_struct * vma, * prev = NULL; |
476 | 477 | ||
477 | if (flags & MCL_FUTURE) | 478 | if (flags & MCL_FUTURE) |
478 | current->mm->def_flags |= VM_LOCKED; | 479 | current->mm->def_flags |= VM_LOCKED | VM_POPULATE; |
479 | else | 480 | else |
480 | current->mm->def_flags &= ~VM_LOCKED; | 481 | current->mm->def_flags &= ~(VM_LOCKED | VM_POPULATE); |
481 | if (flags == MCL_FUTURE) | 482 | if (flags == MCL_FUTURE) |
482 | goto out; | 483 | goto out; |
483 | 484 | ||
484 | for (vma = current->mm->mmap; vma ; vma = prev->vm_next) { | 485 | for (vma = current->mm->mmap; vma ; vma = prev->vm_next) { |
485 | vm_flags_t newflags; | 486 | vm_flags_t newflags; |
486 | 487 | ||
487 | newflags = vma->vm_flags | VM_LOCKED; | 488 | newflags = vma->vm_flags & ~VM_LOCKED; |
488 | if (!(flags & MCL_CURRENT)) | 489 | if (flags & MCL_CURRENT) |
489 | newflags &= ~VM_LOCKED; | 490 | newflags |= VM_LOCKED | VM_POPULATE; |
490 | 491 | ||
491 | /* Ignore errors */ | 492 | /* Ignore errors */ |
492 | mlock_fixup(vma, &prev, vma->vm_start, vma->vm_end, newflags); | 493 | mlock_fixup(vma, &prev, vma->vm_start, vma->vm_end, newflags); |