From: Jeff Dike Fix sys_sigreturn and sys_rt_sigreturn to avoid calling copy_from_user inside a spinlock. We copy the blocked signal mask into a local sigset_t before the spinlock and then just assign from it inside the lock. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton --- 25-akpm/arch/um/sys-i386/signal.c | 39 ++++++++++++++++++++++++++++++-------- 1 files changed, 31 insertions(+), 8 deletions(-) diff -puN arch/um/sys-i386/signal.c~uml-fix-sigreturn-to-not-copy_user-under-a-spinlock arch/um/sys-i386/signal.c --- 25/arch/um/sys-i386/signal.c~uml-fix-sigreturn-to-not-copy_user-under-a-spinlock 2004-11-28 01:17:26.510058264 -0800 +++ 25-akpm/arch/um/sys-i386/signal.c 2004-11-28 01:17:26.514057656 -0800 @@ -305,35 +305,58 @@ long sys_sigreturn(struct pt_regs regs) { unsigned long __user sp = PT_REGS_SP(¤t->thread.regs); struct sigframe __user *frame = (struct sigframe *)(sp - 8); + sigset_t set; struct sigcontext __user *sc = &frame->sc; unsigned long __user *mask = &sc->oldmask; int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); + if(copy_from_user(&set.sig[0], mask, sizeof(&set.sig[0])) || + copy_from_user(&set.sig[1], mask, sig_size)) + goto segfault; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); - copy_from_user(¤t->blocked.sig[0], mask, - sizeof(current->blocked.sig[0])); - copy_from_user(¤t->blocked.sig[1], mask, sig_size); - sigdelsetmask(¤t->blocked, ~_BLOCKABLE); + current->blocked = set; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - copy_sc_from_user(¤t->thread.regs, sc); + + if(copy_sc_from_user(¤t->thread.regs, sc)) + goto segfault; + return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); + + segfault: + force_sig(SIGSEGV, current); + return 0; } long sys_rt_sigreturn(struct pt_regs regs) { unsigned long __user sp = PT_REGS_SP(¤t->thread.regs); struct rt_sigframe __user *frame = (struct rt_sigframe *) (sp - 4); + sigset_t set; struct ucontext __user *uc = &frame->uc; int sig_size = _NSIG_WORDS * sizeof(unsigned long); + if(copy_from_user(&set, &uc->uc_sigmask, sig_size)) + goto segfault; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); - copy_from_user(¤t->blocked, &uc->uc_sigmask, sig_size); - sigdelsetmask(¤t->blocked, ~_BLOCKABLE); + current->blocked = set; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext); + + if(copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext)) + goto segfault; + return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); + + segfault: + force_sig(SIGSEGV, current); + return 0; } /* _