diff options
author | Rasmus Villemoes <linux@rasmusvillemoes.dk> | 2013-04-29 18:08:23 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-29 18:54:37 -0400 |
commit | 84d96d897671cfb386e722acbefdb3a79e115a8a (patch) | |
tree | 0d7559bf9434ccfd933cfd385ff2c3843e6fd396 | |
parent | 4edd7ceff0662afde195da6f6c43e7cbe1ed2dc4 (diff) |
mm: madvise: complete input validation before taking lock
In madvise(), there doesn't seem to be any reason for taking the
¤t->mm->mmap_sem before start and len_in have been validated.
Incidentally, this removes the need for the out: label.
[akpm@linux-foundation.org: s/out_plug/out/, per David]
Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Acked-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Acked-by: David Rientjes <rientjes@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | mm/madvise.c | 31 |
1 files changed, 15 insertions, 16 deletions
diff --git a/mm/madvise.c b/mm/madvise.c index c58c94b56c3d..7055883e6e25 100644 --- a/mm/madvise.c +++ b/mm/madvise.c | |||
@@ -473,27 +473,27 @@ SYSCALL_DEFINE3(madvise, unsigned long, start, size_t, len_in, int, behavior) | |||
473 | if (!madvise_behavior_valid(behavior)) | 473 | if (!madvise_behavior_valid(behavior)) |
474 | return error; | 474 | return error; |
475 | 475 | ||
476 | write = madvise_need_mmap_write(behavior); | ||
477 | if (write) | ||
478 | down_write(¤t->mm->mmap_sem); | ||
479 | else | ||
480 | down_read(¤t->mm->mmap_sem); | ||
481 | |||
482 | if (start & ~PAGE_MASK) | 476 | if (start & ~PAGE_MASK) |
483 | goto out; | 477 | return error; |
484 | len = (len_in + ~PAGE_MASK) & PAGE_MASK; | 478 | len = (len_in + ~PAGE_MASK) & PAGE_MASK; |
485 | 479 | ||
486 | /* Check to see whether len was rounded up from small -ve to zero */ | 480 | /* Check to see whether len was rounded up from small -ve to zero */ |
487 | if (len_in && !len) | 481 | if (len_in && !len) |
488 | goto out; | 482 | return error; |
489 | 483 | ||
490 | end = start + len; | 484 | end = start + len; |
491 | if (end < start) | 485 | if (end < start) |
492 | goto out; | 486 | return error; |
493 | 487 | ||
494 | error = 0; | 488 | error = 0; |
495 | if (end == start) | 489 | if (end == start) |
496 | goto out; | 490 | return error; |
491 | |||
492 | write = madvise_need_mmap_write(behavior); | ||
493 | if (write) | ||
494 | down_write(¤t->mm->mmap_sem); | ||
495 | else | ||
496 | down_read(¤t->mm->mmap_sem); | ||
497 | 497 | ||
498 | /* | 498 | /* |
499 | * If the interval [start,end) covers some unmapped address | 499 | * If the interval [start,end) covers some unmapped address |
@@ -509,14 +509,14 @@ SYSCALL_DEFINE3(madvise, unsigned long, start, size_t, len_in, int, behavior) | |||
509 | /* Still start < end. */ | 509 | /* Still start < end. */ |
510 | error = -ENOMEM; | 510 | error = -ENOMEM; |
511 | if (!vma) | 511 | if (!vma) |
512 | goto out_plug; | 512 | goto out; |
513 | 513 | ||
514 | /* Here start < (end|vma->vm_end). */ | 514 | /* Here start < (end|vma->vm_end). */ |
515 | if (start < vma->vm_start) { | 515 | if (start < vma->vm_start) { |
516 | unmapped_error = -ENOMEM; | 516 | unmapped_error = -ENOMEM; |
517 | start = vma->vm_start; | 517 | start = vma->vm_start; |
518 | if (start >= end) | 518 | if (start >= end) |
519 | goto out_plug; | 519 | goto out; |
520 | } | 520 | } |
521 | 521 | ||
522 | /* Here vma->vm_start <= start < (end|vma->vm_end) */ | 522 | /* Here vma->vm_start <= start < (end|vma->vm_end) */ |
@@ -527,21 +527,20 @@ SYSCALL_DEFINE3(madvise, unsigned long, start, size_t, len_in, int, behavior) | |||
527 | /* Here vma->vm_start <= start < tmp <= (end|vma->vm_end). */ | 527 | /* Here vma->vm_start <= start < tmp <= (end|vma->vm_end). */ |
528 | error = madvise_vma(vma, &prev, start, tmp, behavior); | 528 | error = madvise_vma(vma, &prev, start, tmp, behavior); |
529 | if (error) | 529 | if (error) |
530 | goto out_plug; | 530 | goto out; |
531 | start = tmp; | 531 | start = tmp; |
532 | if (prev && start < prev->vm_end) | 532 | if (prev && start < prev->vm_end) |
533 | start = prev->vm_end; | 533 | start = prev->vm_end; |
534 | error = unmapped_error; | 534 | error = unmapped_error; |
535 | if (start >= end) | 535 | if (start >= end) |
536 | goto out_plug; | 536 | goto out; |
537 | if (prev) | 537 | if (prev) |
538 | vma = prev->vm_next; | 538 | vma = prev->vm_next; |
539 | else /* madvise_remove dropped mmap_sem */ | 539 | else /* madvise_remove dropped mmap_sem */ |
540 | vma = find_vma(current->mm, start); | 540 | vma = find_vma(current->mm, start); |
541 | } | 541 | } |
542 | out_plug: | ||
543 | blk_finish_plug(&plug); | ||
544 | out: | 542 | out: |
543 | blk_finish_plug(&plug); | ||
545 | if (write) | 544 | if (write) |
546 | up_write(¤t->mm->mmap_sem); | 545 | up_write(¤t->mm->mmap_sem); |
547 | else | 546 | else |