From 94d149c34cda933ff5096aca94bb23bf68602f4e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 12 May 2008 16:33:33 -0700 Subject: 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 Signed-off-by: David S. Miller --- arch/sparc/kernel/sys_sparc.c | 48 ++++----------------------------------- arch/sparc64/kernel/sys_sparc.c | 36 ++++------------------------- arch/sparc64/kernel/sys_sparc32.c | 33 ++------------------------- include/asm-sparc/mman.h | 5 ++-- include/asm-sparc64/mman.h | 5 ++-- 5 files changed, 15 insertions(+), 112 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: return err; } -int sparc_mmap_check(unsigned long addr, unsigned long len, unsigned long flags) +int sparc_mmap_check(unsigned long addr, unsigned long len) { if (ARCH_SUN4C_SUN4 && (len > 0x20000000 || @@ -295,52 +295,14 @@ asmlinkage unsigned long sparc_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr) { - struct vm_area_struct *vma; unsigned long ret = -EINVAL; - if (ARCH_SUN4C_SUN4) { - if (old_len > 0x20000000 || new_len > 0x20000000) - goto out; - if (addr < 0xe0000000 && addr + old_len > 0x20000000) - goto out; - } - if (old_len > TASK_SIZE - PAGE_SIZE || - new_len > TASK_SIZE - PAGE_SIZE) + + if (unlikely(sparc_mmap_check(addr, old_len))) + goto out; + if (unlikely(sparc_mmap_check(new_addr, new_len))) goto out; down_write(¤t->mm->mmap_sem); - if (flags & MREMAP_FIXED) { - if (ARCH_SUN4C_SUN4 && - new_addr < 0xe0000000 && - new_addr + new_len > 0x20000000) - goto out_sem; - if (new_addr + new_len > TASK_SIZE - PAGE_SIZE) - goto out_sem; - } else if ((ARCH_SUN4C_SUN4 && addr < 0xe0000000 && - addr + new_len > 0x20000000) || - addr + new_len > TASK_SIZE - PAGE_SIZE) { - unsigned long map_flags = 0; - struct file *file = NULL; - - ret = -ENOMEM; - if (!(flags & MREMAP_MAYMOVE)) - goto out_sem; - - vma = find_vma(current->mm, addr); - if (vma) { - if (vma->vm_flags & VM_SHARED) - map_flags |= MAP_SHARED; - file = vma->vm_file; - } - - new_addr = get_unmapped_area(file, addr, new_len, - vma ? vma->vm_pgoff : 0, - map_flags); - ret = new_addr; - if (new_addr & ~PAGE_MASK) - goto out_sem; - flags |= MREMAP_FIXED; - } ret = do_mremap(addr, old_len, new_len, flags, new_addr); -out_sem: up_write(¤t->mm->mmap_sem); out: 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) return ret; } -int sparc64_mmap_check(unsigned long addr, unsigned long len, - unsigned long flags) +int sparc64_mmap_check(unsigned long addr, unsigned long len) { if (test_thread_flag(TIF_32BIT)) { if (len >= STACK_TOP32) @@ -609,46 +608,19 @@ asmlinkage unsigned long sys64_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr) { - struct vm_area_struct *vma; unsigned long ret = -EINVAL; if (test_thread_flag(TIF_32BIT)) goto out; if (unlikely(new_len >= VA_EXCLUDE_START)) goto out; - if (unlikely(invalid_64bit_range(addr, old_len))) + if (unlikely(sparc64_mmap_check(addr, old_len))) + goto out; + if (unlikely(sparc64_mmap_check(new_addr, new_len))) goto out; down_write(¤t->mm->mmap_sem); - if (flags & MREMAP_FIXED) { - if (invalid_64bit_range(new_addr, new_len)) - goto out_sem; - } else if (invalid_64bit_range(addr, new_len)) { - unsigned long map_flags = 0; - struct file *file = NULL; - - ret = -ENOMEM; - if (!(flags & MREMAP_MAYMOVE)) - goto out_sem; - - vma = find_vma(current->mm, addr); - if (vma) { - if (vma->vm_flags & VM_SHARED) - map_flags |= MAP_SHARED; - file = vma->vm_file; - } - - /* MREMAP_FIXED checked above. */ - new_addr = get_unmapped_area(file, addr, new_len, - vma ? vma->vm_pgoff : 0, - map_flags); - ret = new_addr; - if (new_addr & ~PAGE_MASK) - goto out_sem; - flags |= MREMAP_FIXED; - } ret = do_mremap(addr, old_len, new_len, flags, new_addr); -out_sem: up_write(¤t->mm->mmap_sem); out: 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, unsigned long old_len, unsigned long new_len, unsigned long flags, u32 __new_addr) { - struct vm_area_struct *vma; unsigned long ret = -EINVAL; unsigned long new_addr = __new_addr; - if (old_len > STACK_TOP32 || new_len > STACK_TOP32) + if (unlikely(sparc64_mmap_check(addr, old_len))) goto out; - if (addr > STACK_TOP32 - old_len) + if (unlikely(sparc64_mmap_check(new_addr, new_len))) goto out; down_write(¤t->mm->mmap_sem); - if (flags & MREMAP_FIXED) { - if (new_addr > STACK_TOP32 - new_len) - goto out_sem; - } else if (addr > STACK_TOP32 - new_len) { - unsigned long map_flags = 0; - struct file *file = NULL; - - ret = -ENOMEM; - if (!(flags & MREMAP_MAYMOVE)) - goto out_sem; - - vma = find_vma(current->mm, addr); - if (vma) { - if (vma->vm_flags & VM_SHARED) - map_flags |= MAP_SHARED; - file = vma->vm_file; - } - - /* MREMAP_FIXED checked above. */ - new_addr = get_unmapped_area(file, addr, new_len, - vma ? vma->vm_pgoff : 0, - map_flags); - ret = new_addr; - if (new_addr & ~PAGE_MASK) - goto out_sem; - flags |= MREMAP_FIXED; - } ret = do_mremap(addr, old_len, new_len, flags, new_addr); -out_sem: up_write(¤t->mm->mmap_sem); out: return ret; diff --git a/include/asm-sparc/mman.h b/include/asm-sparc/mman.h index e18be984c01d..3d16b40bb8ef 100644 --- a/include/asm-sparc/mman.h +++ b/include/asm-sparc/mman.h @@ -24,9 +24,8 @@ #ifdef __KERNEL__ #ifndef __ASSEMBLY__ -#define arch_mmap_check sparc_mmap_check -int sparc_mmap_check(unsigned long addr, unsigned long len, - unsigned long flags); +#define arch_mmap_check(addr,len,flags) sparc_mmap_check(addr,len) +int sparc_mmap_check(unsigned long addr, unsigned long len); #endif #endif diff --git a/include/asm-sparc64/mman.h b/include/asm-sparc64/mman.h index e584563b56eb..625be4d61baf 100644 --- a/include/asm-sparc64/mman.h +++ b/include/asm-sparc64/mman.h @@ -24,9 +24,8 @@ #ifdef __KERNEL__ #ifndef __ASSEMBLY__ -#define arch_mmap_check sparc64_mmap_check -int sparc64_mmap_check(unsigned long addr, unsigned long len, - unsigned long flags); +#define arch_mmap_check(addr,len,flags) sparc64_mmap_check(addr,len) +int sparc64_mmap_check(unsigned long addr, unsigned long len); #endif #endif -- cgit v1.2.3 From 4978db5bd964d90265f957f980ab2b0771ca2b9f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 12 May 2008 16:51:15 -0700 Subject: lmb: Fix inconsistent alignment of size argument. When allocating, if we will align up the size when making the reservation, we should also align the size for the check that the space is actually available. The simplest thing is to just aling the size up from the beginning, then we can use plain 'size' throughout. Signed-off-by: David S. Miller --- lib/lmb.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/lmb.c b/lib/lmb.c index 83287d3869a3..93445dc8f818 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -286,8 +286,7 @@ static u64 __init lmb_alloc_nid_unreserved(u64 start, u64 end, j = lmb_overlaps_region(&lmb.reserved, base, size); if (j < 0) { /* this area isn't reserved, take it */ - if (lmb_add_region(&lmb.reserved, base, - lmb_align_up(size, align)) < 0) + if (lmb_add_region(&lmb.reserved, base, size) < 0) base = ~(u64)0; return base; } @@ -333,6 +332,10 @@ u64 __init lmb_alloc_nid(u64 size, u64 align, int nid, struct lmb_region *mem = &lmb.memory; int i; + BUG_ON(0 == size); + + size = lmb_align_up(size, align); + for (i = 0; i < mem->cnt; i++) { u64 ret = lmb_alloc_nid_region(&mem->region[i], nid_range, @@ -370,6 +373,8 @@ u64 __init __lmb_alloc_base(u64 size, u64 align, u64 max_addr) BUG_ON(0 == size); + size = lmb_align_up(size, align); + /* On some platforms, make sure we allocate lowmem */ /* Note that LMB_REAL_LIMIT may be LMB_ALLOC_ANYWHERE */ if (max_addr == LMB_ALLOC_ANYWHERE) @@ -393,8 +398,7 @@ u64 __init __lmb_alloc_base(u64 size, u64 align, u64 max_addr) j = lmb_overlaps_region(&lmb.reserved, base, size); if (j < 0) { /* this area isn't reserved, take it */ - if (lmb_add_region(&lmb.reserved, base, - lmb_align_up(size, align)) < 0) + if (lmb_add_region(&lmb.reserved, base, size) < 0) return 0; return base; } -- cgit v1.2.3 From faa6cfde747ba6d37a0889cbe85881c80806d355 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 12 May 2008 17:21:55 -0700 Subject: lmb: Make lmb debugging more useful. Having to muck with the build and set DEBUG just to get lmb_dump_all() to print things isn't very useful. So use pr_info() and use an early boot param "lmb=debug" so we can simply ask users to reboot with this option when we need some debugging from them. Signed-off-by: David S. Miller --- lib/lmb.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/lib/lmb.c b/lib/lmb.c index 93445dc8f818..867f7b5a8231 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -19,31 +19,42 @@ struct lmb lmb; +static int lmb_debug; + +static int __init early_lmb(char *p) +{ + if (p && strstr(p, "debug")) + lmb_debug = 1; + return 0; +} +early_param("lmb", early_lmb); + void lmb_dump_all(void) { -#ifdef DEBUG unsigned long i; - pr_debug("lmb_dump_all:\n"); - pr_debug(" memory.cnt = 0x%lx\n", lmb.memory.cnt); - pr_debug(" memory.size = 0x%llx\n", + if (!lmb_debug) + return; + + pr_info("lmb_dump_all:\n"); + pr_info(" memory.cnt = 0x%lx\n", lmb.memory.cnt); + pr_info(" memory.size = 0x%llx\n", (unsigned long long)lmb.memory.size); for (i=0; i < lmb.memory.cnt ;i++) { - pr_debug(" memory.region[0x%x].base = 0x%llx\n", + pr_info(" memory.region[0x%lx].base = 0x%llx\n", i, (unsigned long long)lmb.memory.region[i].base); - pr_debug(" .size = 0x%llx\n", + pr_info(" .size = 0x%llx\n", (unsigned long long)lmb.memory.region[i].size); } - pr_debug(" reserved.cnt = 0x%lx\n", lmb.reserved.cnt); - pr_debug(" reserved.size = 0x%lx\n", lmb.reserved.size); + pr_info(" reserved.cnt = 0x%lx\n", lmb.reserved.cnt); + pr_info(" reserved.size = 0x%lx\n", lmb.reserved.size); for (i=0; i < lmb.reserved.cnt ;i++) { - pr_debug(" reserved.region[0x%x].base = 0x%llx\n", + pr_info(" reserved.region[0x%lx].base = 0x%llx\n", i, (unsigned long long)lmb.reserved.region[i].base); - pr_debug(" .size = 0x%llx\n", + pr_info(" .size = 0x%llx\n", (unsigned long long)lmb.reserved.region[i].size); } -#endif /* DEBUG */ } static unsigned long lmb_addrs_overlap(u64 base1, u64 size1, u64 base2, -- cgit v1.2.3 From 9a28dbf8af11d127bf1c644143e7882cb91515dd Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 12 May 2008 22:45:15 -0700 Subject: sparc64: Use a TS_RESTORE_SIGMASK This mirrors x86 changeset 5a8da0ea82db6fa9737041381079fd16f25dcce2 ("signals: x86 TS_RESTORE_SIGMASK") on sparc64. Signed-off-by: David S. Miller --- arch/sparc64/kernel/rtrap.S | 6 +++--- arch/sparc64/kernel/signal.c | 21 +++++++++++---------- arch/sparc64/kernel/signal32.c | 13 ++++++------- include/asm-sparc64/thread_info.h | 28 ++++++++++++++++++++++++---- 4 files changed, 44 insertions(+), 24 deletions(-) diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S index b9b785fd8b46..16689b2930db 100644 --- a/arch/sparc64/kernel/rtrap.S +++ b/arch/sparc64/kernel/rtrap.S @@ -46,7 +46,7 @@ __handle_user_windows: wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate ldx [%g6 + TI_FLAGS], %l0 -1: andcc %l0, (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), %g0 +1: andcc %l0, _TIF_SIGPENDING, %g0 be,pt %xcc, __handle_user_windows_continue nop mov %l5, %o1 @@ -86,7 +86,7 @@ __handle_perfctrs: wrpr %g0, RTRAP_PSTATE, %pstate wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate ldx [%g6 + TI_FLAGS], %l0 -1: andcc %l0, (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), %g0 +1: andcc %l0, _TIF_SIGPENDING, %g0 be,pt %xcc, __handle_perfctrs_continue sethi %hi(TSTATE_PEF), %o0 @@ -195,7 +195,7 @@ __handle_preemption_continue: andcc %l1, %o0, %g0 andcc %l0, _TIF_NEED_RESCHED, %g0 bne,pn %xcc, __handle_preemption - andcc %l0, (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), %g0 + andcc %l0, _TIF_SIGPENDING, %g0 bne,pn %xcc, __handle_signal __handle_signal_continue: ldub [%g6 + TI_WSAVED], %o2 diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index 2378482c2aab..6e4dc67d16af 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -247,7 +247,9 @@ static long _sigpause_common(old_sigset_t set) current->state = TASK_INTERRUPTIBLE; schedule(); - set_thread_flag(TIF_RESTORE_SIGMASK); + + set_restore_sigmask(); + return -ERESTARTNOHAND; } @@ -537,7 +539,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) } else restart_syscall = 0; - if (test_thread_flag(TIF_RESTORE_SIGMASK)) + if (current_thread_info()->status & TS_RESTORE_SIGMASK) oldset = ¤t->saved_sigmask; else oldset = ¤t->blocked; @@ -566,13 +568,12 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) syscall_restart(orig_i0, regs, &ka.sa); handle_signal(signr, &ka, &info, oldset, regs); - /* a signal was successfully delivered; the saved + /* A signal was successfully delivered; the saved * sigmask will have been stored in the signal frame, * and will be restored by sigreturn, so we can simply - * clear the TIF_RESTORE_SIGMASK flag. + * clear the TS_RESTORE_SIGMASK flag. */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) - clear_thread_flag(TIF_RESTORE_SIGMASK); + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; return; } if (restart_syscall && @@ -591,17 +592,17 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) regs->tnpc -= 4; } - /* if there's no signal to deliver, we just put the saved sigmask + /* If there's no signal to deliver, we just put the saved sigmask * back */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) { - clear_thread_flag(TIF_RESTORE_SIGMASK); + if (current_thread_info()->status & TS_RESTORE_SIGMASK) { + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); } } void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long thread_info_flags) { - if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) + if (thread_info_flags & _TIF_SIGPENDING) do_signal(regs, orig_i0); } diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index 3f19e9af3d1b..97cdd1bf4a10 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -788,13 +788,12 @@ void do_signal32(sigset_t *oldset, struct pt_regs * regs, syscall_restart32(orig_i0, regs, &ka.sa); handle_signal32(signr, &ka, &info, oldset, regs); - /* a signal was successfully delivered; the saved + /* A signal was successfully delivered; the saved * sigmask will have been stored in the signal frame, * and will be restored by sigreturn, so we can simply - * clear the TIF_RESTORE_SIGMASK flag. + * clear the TS_RESTORE_SIGMASK flag. */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) - clear_thread_flag(TIF_RESTORE_SIGMASK); + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; return; } if (restart_syscall && @@ -813,11 +812,11 @@ void do_signal32(sigset_t *oldset, struct pt_regs * regs, regs->tnpc -= 4; } - /* if there's no signal to deliver, we just put the saved sigmask + /* If there's no signal to deliver, we just put the saved sigmask * back */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) { - clear_thread_flag(TIF_RESTORE_SIGMASK); + if (current_thread_info()->status & TS_RESTORE_SIGMASK) { + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); } } diff --git a/include/asm-sparc64/thread_info.h b/include/asm-sparc64/thread_info.h index 71e42d1a80d9..e5873e385306 100644 --- a/include/asm-sparc64/thread_info.h +++ b/include/asm-sparc64/thread_info.h @@ -38,7 +38,7 @@ struct thread_info { struct task_struct *task; unsigned long flags; __u8 fpsaved[7]; - __u8 pad; + __u8 status; unsigned long ksp; /* D$ line 2 */ @@ -217,7 +217,7 @@ register struct thread_info *current_thread_info_reg asm("g6"); * nop */ #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ -#define TIF_RESTORE_SIGMASK 1 /* restore signal mask in do_signal() */ +/* flags bit 1 is available */ #define TIF_SIGPENDING 2 /* signal pending */ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_PERFCTR 4 /* performance counters active */ @@ -244,14 +244,34 @@ register struct thread_info *current_thread_info_reg asm("g6"); #define _TIF_32BIT (1<status |= TS_RESTORE_SIGMASK; + set_bit(TIF_SIGPENDING, &ti->flags); +} +#endif /* !__ASSEMBLY__ */ + #endif /* __KERNEL__ */ #endif /* _ASM_THREAD_INFO_H */ -- cgit v1.2.3