aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-05-12 19:33:33 -0400
committerDavid S. Miller <davem@davemloft.net>2008-05-12 19:33:33 -0400
commit94d149c34cda933ff5096aca94bb23bf68602f4e (patch)
tree2c1a33482cd6961b45296979b898881a7a4d71d3 /arch
parentc714a534d85576af21b06be605ca55cb2fb887ee (diff)
sparc: Fix mremap address range validation.
Just like mmap, we need to validate address ranges regardless of MAP_FIXED. sparc{,64}_mmap_check()'s flag argument is unused, remove. Based upon a report and preliminary patch by Jan Lieskovsky <jlieskov@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch')
-rw-r--r--arch/sparc/kernel/sys_sparc.c48
-rw-r--r--arch/sparc64/kernel/sys_sparc.c36
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c33
3 files changed, 11 insertions, 106 deletions
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c
index e995491c4436..3c6b49a53ae8 100644
--- a/arch/sparc/kernel/sys_sparc.c
+++ b/arch/sparc/kernel/sys_sparc.c
@@ -219,7 +219,7 @@ out:
219 return err; 219 return err;
220} 220}
221 221
222int sparc_mmap_check(unsigned long addr, unsigned long len, unsigned long flags) 222int sparc_mmap_check(unsigned long addr, unsigned long len)
223{ 223{
224 if (ARCH_SUN4C_SUN4 && 224 if (ARCH_SUN4C_SUN4 &&
225 (len > 0x20000000 || 225 (len > 0x20000000 ||
@@ -295,52 +295,14 @@ asmlinkage unsigned long sparc_mremap(unsigned long addr,
295 unsigned long old_len, unsigned long new_len, 295 unsigned long old_len, unsigned long new_len,
296 unsigned long flags, unsigned long new_addr) 296 unsigned long flags, unsigned long new_addr)
297{ 297{
298 struct vm_area_struct *vma;
299 unsigned long ret = -EINVAL; 298 unsigned long ret = -EINVAL;
300 if (ARCH_SUN4C_SUN4) { 299
301 if (old_len > 0x20000000 || new_len > 0x20000000) 300 if (unlikely(sparc_mmap_check(addr, old_len)))
302 goto out; 301 goto out;
303 if (addr < 0xe0000000 && addr + old_len > 0x20000000) 302 if (unlikely(sparc_mmap_check(new_addr, new_len)))
304 goto out;
305 }
306 if (old_len > TASK_SIZE - PAGE_SIZE ||
307 new_len > TASK_SIZE - PAGE_SIZE)
308 goto out; 303 goto out;
309 down_write(&current->mm->mmap_sem); 304 down_write(&current->mm->mmap_sem);
310 if (flags & MREMAP_FIXED) {
311 if (ARCH_SUN4C_SUN4 &&
312 new_addr < 0xe0000000 &&
313 new_addr + new_len > 0x20000000)
314 goto out_sem;
315 if (new_addr + new_len > TASK_SIZE - PAGE_SIZE)
316 goto out_sem;
317 } else if ((ARCH_SUN4C_SUN4 && addr < 0xe0000000 &&
318 addr + new_len > 0x20000000) ||
319 addr + new_len > TASK_SIZE - PAGE_SIZE) {
320 unsigned long map_flags = 0;
321 struct file *file = NULL;
322
323 ret = -ENOMEM;
324 if (!(flags & MREMAP_MAYMOVE))
325 goto out_sem;
326
327 vma = find_vma(current->mm, addr);
328 if (vma) {
329 if (vma->vm_flags & VM_SHARED)
330 map_flags |= MAP_SHARED;
331 file = vma->vm_file;
332 }
333
334 new_addr = get_unmapped_area(file, addr, new_len,
335 vma ? vma->vm_pgoff : 0,
336 map_flags);
337 ret = new_addr;
338 if (new_addr & ~PAGE_MASK)
339 goto out_sem;
340 flags |= MREMAP_FIXED;
341 }
342 ret = do_mremap(addr, old_len, new_len, flags, new_addr); 305 ret = do_mremap(addr, old_len, new_len, flags, new_addr);
343out_sem:
344 up_write(&current->mm->mmap_sem); 306 up_write(&current->mm->mmap_sem);
345out: 307out:
346 return ret; 308 return ret;
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index 0dbc941f130e..ac1bff58c1ac 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -542,8 +542,7 @@ asmlinkage long sparc64_personality(unsigned long personality)
542 return ret; 542 return ret;
543} 543}
544 544
545int sparc64_mmap_check(unsigned long addr, unsigned long len, 545int sparc64_mmap_check(unsigned long addr, unsigned long len)
546 unsigned long flags)
547{ 546{
548 if (test_thread_flag(TIF_32BIT)) { 547 if (test_thread_flag(TIF_32BIT)) {
549 if (len >= STACK_TOP32) 548 if (len >= STACK_TOP32)
@@ -609,46 +608,19 @@ asmlinkage unsigned long sys64_mremap(unsigned long addr,
609 unsigned long old_len, unsigned long new_len, 608 unsigned long old_len, unsigned long new_len,
610 unsigned long flags, unsigned long new_addr) 609 unsigned long flags, unsigned long new_addr)
611{ 610{
612 struct vm_area_struct *vma;
613 unsigned long ret = -EINVAL; 611 unsigned long ret = -EINVAL;
614 612
615 if (test_thread_flag(TIF_32BIT)) 613 if (test_thread_flag(TIF_32BIT))
616 goto out; 614 goto out;
617 if (unlikely(new_len >= VA_EXCLUDE_START)) 615 if (unlikely(new_len >= VA_EXCLUDE_START))
618 goto out; 616 goto out;
619 if (unlikely(invalid_64bit_range(addr, old_len))) 617 if (unlikely(sparc64_mmap_check(addr, old_len)))
618 goto out;
619 if (unlikely(sparc64_mmap_check(new_addr, new_len)))
620 goto out; 620 goto out;
621 621
622 down_write(&current->mm->mmap_sem); 622 down_write(&current->mm->mmap_sem);
623 if (flags & MREMAP_FIXED) {
624 if (invalid_64bit_range(new_addr, new_len))
625 goto out_sem;
626 } else if (invalid_64bit_range(addr, new_len)) {
627 unsigned long map_flags = 0;
628 struct file *file = NULL;
629
630 ret = -ENOMEM;
631 if (!(flags & MREMAP_MAYMOVE))
632 goto out_sem;
633
634 vma = find_vma(current->mm, addr);
635 if (vma) {
636 if (vma->vm_flags & VM_SHARED)
637 map_flags |= MAP_SHARED;
638 file = vma->vm_file;
639 }
640
641 /* MREMAP_FIXED checked above. */
642 new_addr = get_unmapped_area(file, addr, new_len,
643 vma ? vma->vm_pgoff : 0,
644 map_flags);
645 ret = new_addr;
646 if (new_addr & ~PAGE_MASK)
647 goto out_sem;
648 flags |= MREMAP_FIXED;
649 }
650 ret = do_mremap(addr, old_len, new_len, flags, new_addr); 623 ret = do_mremap(addr, old_len, new_len, flags, new_addr);
651out_sem:
652 up_write(&current->mm->mmap_sem); 624 up_write(&current->mm->mmap_sem);
653out: 625out:
654 return ret; 626 return ret;
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 1aa4288125f2..ba5bd626b39e 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -867,44 +867,15 @@ asmlinkage unsigned long sys32_mremap(unsigned long addr,
867 unsigned long old_len, unsigned long new_len, 867 unsigned long old_len, unsigned long new_len,
868 unsigned long flags, u32 __new_addr) 868 unsigned long flags, u32 __new_addr)
869{ 869{
870 struct vm_area_struct *vma;
871 unsigned long ret = -EINVAL; 870 unsigned long ret = -EINVAL;
872 unsigned long new_addr = __new_addr; 871 unsigned long new_addr = __new_addr;
873 872
874 if (old_len > STACK_TOP32 || new_len > STACK_TOP32) 873 if (unlikely(sparc64_mmap_check(addr, old_len)))
875 goto out; 874 goto out;
876 if (addr > STACK_TOP32 - old_len) 875 if (unlikely(sparc64_mmap_check(new_addr, new_len)))
877 goto out; 876 goto out;
878 down_write(&current->mm->mmap_sem); 877 down_write(&current->mm->mmap_sem);
879 if (flags & MREMAP_FIXED) {
880 if (new_addr > STACK_TOP32 - new_len)
881 goto out_sem;
882 } else if (addr > STACK_TOP32 - new_len) {
883 unsigned long map_flags = 0;
884 struct file *file = NULL;
885
886 ret = -ENOMEM;
887 if (!(flags & MREMAP_MAYMOVE))
888 goto out_sem;
889
890 vma = find_vma(current->mm, addr);
891 if (vma) {
892 if (vma->vm_flags & VM_SHARED)
893 map_flags |= MAP_SHARED;
894 file = vma->vm_file;
895 }
896
897 /* MREMAP_FIXED checked above. */
898 new_addr = get_unmapped_area(file, addr, new_len,
899 vma ? vma->vm_pgoff : 0,
900 map_flags);
901 ret = new_addr;
902 if (new_addr & ~PAGE_MASK)
903 goto out_sem;
904 flags |= MREMAP_FIXED;
905 }
906 ret = do_mremap(addr, old_len, new_len, flags, new_addr); 878 ret = do_mremap(addr, old_len, new_len, flags, new_addr);
907out_sem:
908 up_write(&current->mm->mmap_sem); 879 up_write(&current->mm->mmap_sem);
909out: 880out:
910 return ret; 881 return ret;