aboutsummaryrefslogtreecommitdiffstats
path: root/mm/mlock.c
diff options
context:
space:
mode:
authorMichel Lespinasse <walken@google.com>2013-02-22 19:32:46 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-23 20:50:11 -0500
commit1869305009857cdeaabe6283bcdc2359c5784543 (patch)
treea8a500c71e7aa3a645322635f3d591c16601af27 /mm/mlock.c
parentcea10a19b7972a1954c4a2d05a7de8db48b444fb (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.c19
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);