diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-06-16 23:00:36 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-06-16 23:00:36 +0000 |
commit | 14dd2ec093cfabda3ae7efeeaf0e23c66ebaccc0 (patch) | |
tree | 9a9ce5cff6ef92faa6e07a82785b9a6d6838f7e4 /arch/mips | |
parent | 847290510f811c572cc2aa80c1f02a04721410b1 (diff) |
Merge with 2.4.0-test1.
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/kernel/signal.c | 37 | ||||
-rw-r--r-- | arch/mips/mm/fault.c | 25 |
2 files changed, 51 insertions, 11 deletions
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 81ff3173d..c145b3343 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -39,6 +39,41 @@ extern asmlinkage int restore_fp_context(struct sigcontext *sc); extern asmlinkage void syscall_trace(void); +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + /* * Atomically swap in the new signal mask, and wait for a signal. */ @@ -442,7 +477,7 @@ setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, } /* Create siginfo. */ - err |= __copy_to_user(&frame->rs_info, info, sizeof(*info)); + err |= copy_siginfo_to_user(&frame->rs_info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->rs_uc.uc_flags); diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index e2d74fd11..6c9b46b82 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -1,10 +1,9 @@ -/* $Id: fault.c,v 1.15 2000/02/04 07:40:23 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle + * Copyright (C) 1995 - 2000 by Ralf Baechle */ #include <linux/signal.h> #include <linux/sched.h> @@ -47,9 +46,10 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write, struct vm_area_struct * vma; struct task_struct *tsk = current; struct mm_struct *mm = tsk->mm; - int si_code = SEGV_MAPERR; unsigned long fixup; + siginfo_t info; + info.si_code = SEGV_MAPERR; /* * If we're in an interrupt or have no user * context, we must not take the fault.. @@ -75,7 +75,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write, * we can handle it.. */ good_area: - si_code = SEGV_ACCERR; + info.si_code = SEGV_ACCERR; if (write) { if (!(vma->vm_flags & VM_WRITE)) @@ -126,10 +126,11 @@ bad_area: (unsigned long) regs->cp0_epc, (unsigned long) regs->regs[31]); #endif - si.si_signo = SIGSEGV; - si.si_code = si_code; - si.si_addr = (void *) address; - force_sig_info(SIGSEGV, &si, tsk); + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* info.si_code has been set above */ + info.si_addr = (void *) address; + force_sig_info(SIGSEGV, &info, tsk); return; } @@ -177,7 +178,11 @@ do_sigbus: * or user mode. */ tsk->thread.cp0_badvaddr = address; - force_sig(SIGBUS, tsk); + info.si_code = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRERR; + info.si_addr = (void *) address; + force_sig_info(SIGBUS, &info, tsk); /* Kernel mode? Handle exceptions or die */ if (!user_mode(regs)) |