summaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel/signal.c')
-rw-r--r--arch/i386/kernel/signal.c43
1 files changed, 40 insertions, 3 deletions
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index 4e813fac7..c35f5bae8 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -4,6 +4,8 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*
* 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
+ * Pentium III support by Ingo Molnar, modifications and OS Exception support
+ * by Goutham Rao
*/
#include <linux/config.h>
@@ -30,6 +32,41 @@ asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
int options, unsigned long *ru);
asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
+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.
*/
@@ -155,7 +192,7 @@ static inline int restore_i387_hard(struct _fpstate *buf)
{
struct task_struct *tsk = current;
clear_fpu(tsk);
- return __copy_from_user(&tsk->thread.i387.hard, buf, sizeof(*buf));
+ return i387_user_to_hard(&tsk->thread.i387.hard, buf);
}
static inline int restore_i387(struct _fpstate *buf)
@@ -309,7 +346,7 @@ static inline int save_i387_hard(struct _fpstate * buf)
unlazy_fpu(tsk);
tsk->thread.i387.hard.status = tsk->thread.i387.hard.swd;
- if (__copy_to_user(buf, &tsk->thread.i387.hard, sizeof(*buf)))
+ if (i387_hard_to_user(buf, &tsk->thread.i387.hard))
return -1;
return 1;
}
@@ -491,7 +528,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
&frame->sig);
err |= __put_user(&frame->info, &frame->pinfo);
err |= __put_user(&frame->uc, &frame->puc);
- err |= __copy_to_user(&frame->info, info, sizeof(*info));
+ err |= copy_siginfo_to_user(&frame->info, info);
if (err)
goto give_sigsegv;