Merge tag 'gcc-plugins-v4.9-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / arch / mips / kernel / signal32.c
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 1991, 1992  Linus Torvalds
7  * Copyright (C) 1994 - 2000, 2006  Ralf Baechle
8  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
9  * Copyright (C) 2016, Imagination Technologies Ltd.
10  */
11 #include <linux/compiler.h>
12 #include <linux/errno.h>
13 #include <linux/kernel.h>
14 #include <linux/signal.h>
15 #include <linux/syscalls.h>
16
17 #include <asm/compat.h>
18 #include <asm/compat-signal.h>
19 #include <asm/uaccess.h>
20 #include <asm/unistd.h>
21
22 #include "signal-common.h"
23
24 /* 32-bit compatibility types */
25
26 typedef unsigned int __sighandler32_t;
27 typedef void (*vfptr_t)(void);
28
29 /*
30  * Atomically swap in the new signal mask, and wait for a signal.
31  */
32
33 asmlinkage int sys32_sigsuspend(compat_sigset_t __user *uset)
34 {
35         return compat_sys_rt_sigsuspend(uset, sizeof(compat_sigset_t));
36 }
37
38 SYSCALL_DEFINE3(32_sigaction, long, sig, const struct compat_sigaction __user *, act,
39         struct compat_sigaction __user *, oact)
40 {
41         struct k_sigaction new_ka, old_ka;
42         int ret;
43         int err = 0;
44
45         if (act) {
46                 old_sigset_t mask;
47                 s32 handler;
48
49                 if (!access_ok(VERIFY_READ, act, sizeof(*act)))
50                         return -EFAULT;
51                 err |= __get_user(handler, &act->sa_handler);
52                 new_ka.sa.sa_handler = (void __user *)(s64)handler;
53                 err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
54                 err |= __get_user(mask, &act->sa_mask.sig[0]);
55                 if (err)
56                         return -EFAULT;
57
58                 siginitset(&new_ka.sa.sa_mask, mask);
59         }
60
61         ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
62
63         if (!ret && oact) {
64                 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
65                         return -EFAULT;
66                 err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
67                 err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
68                                   &oact->sa_handler);
69                 err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
70                 err |= __put_user(0, &oact->sa_mask.sig[1]);
71                 err |= __put_user(0, &oact->sa_mask.sig[2]);
72                 err |= __put_user(0, &oact->sa_mask.sig[3]);
73                 if (err)
74                         return -EFAULT;
75         }
76
77         return ret;
78 }
79
80 int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
81 {
82         int err;
83
84         if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
85                 return -EFAULT;
86
87         /* If you change siginfo_t structure, please be sure
88            this code is fixed accordingly.
89            It should never copy any pad contained in the structure
90            to avoid security leaks, but must copy the generic
91            3 ints plus the relevant union member.
92            This routine must convert siginfo from 64bit to 32bit as well
93            at the same time.  */
94         err = __put_user(from->si_signo, &to->si_signo);
95         err |= __put_user(from->si_errno, &to->si_errno);
96         err |= __put_user((short)from->si_code, &to->si_code);
97         if (from->si_code < 0)
98                 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
99         else {
100                 switch (from->si_code >> 16) {
101                 case __SI_TIMER >> 16:
102                         err |= __put_user(from->si_tid, &to->si_tid);
103                         err |= __put_user(from->si_overrun, &to->si_overrun);
104                         err |= __put_user(from->si_int, &to->si_int);
105                         break;
106                 case __SI_CHLD >> 16:
107                         err |= __put_user(from->si_utime, &to->si_utime);
108                         err |= __put_user(from->si_stime, &to->si_stime);
109                         err |= __put_user(from->si_status, &to->si_status);
110                 default:
111                         err |= __put_user(from->si_pid, &to->si_pid);
112                         err |= __put_user(from->si_uid, &to->si_uid);
113                         break;
114                 case __SI_FAULT >> 16:
115                         err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
116                         break;
117                 case __SI_POLL >> 16:
118                         err |= __put_user(from->si_band, &to->si_band);
119                         err |= __put_user(from->si_fd, &to->si_fd);
120                         break;
121                 case __SI_RT >> 16: /* This is not generated by the kernel as of now.  */
122                 case __SI_MESGQ >> 16:
123                         err |= __put_user(from->si_pid, &to->si_pid);
124                         err |= __put_user(from->si_uid, &to->si_uid);
125                         err |= __put_user(from->si_int, &to->si_int);
126                         break;
127                 case __SI_SYS >> 16:
128                         err |= __copy_to_user(&to->si_call_addr, &from->si_call_addr,
129                                               sizeof(compat_uptr_t));
130                         err |= __put_user(from->si_syscall, &to->si_syscall);
131                         err |= __put_user(from->si_arch, &to->si_arch);
132                         break;
133                 }
134         }
135         return err;
136 }
137
138 int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
139 {
140         if (copy_from_user(to, from, 3*sizeof(int)) ||
141             copy_from_user(to->_sifields._pad,
142                            from->_sifields._pad, SI_PAD_SIZE32))
143                 return -EFAULT;
144
145         return 0;
146 }