GNU Linux-libre 4.14.266-gnu1
[releases.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 <linux/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(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 (siginfo_layout(from->si_signo, from->si_code)) {
101                 case SIL_TIMER:
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 SIL_CHLD:
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                 case SIL_KILL:
111                         err |= __put_user(from->si_pid, &to->si_pid);
112                         err |= __put_user(from->si_uid, &to->si_uid);
113                         break;
114                 case SIL_FAULT:
115                         err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
116                         break;
117                 case SIL_POLL:
118                         err |= __put_user(from->si_band, &to->si_band);
119                         err |= __put_user(from->si_fd, &to->si_fd);
120                         break;
121                 case SIL_RT:
122                         err |= __put_user(from->si_pid, &to->si_pid);
123                         err |= __put_user(from->si_uid, &to->si_uid);
124                         err |= __put_user(from->si_int, &to->si_int);
125                         break;
126                 case SIL_SYS:
127                         err |= __copy_to_user(&to->si_call_addr, &from->si_call_addr,
128                                               sizeof(compat_uptr_t));
129                         err |= __put_user(from->si_syscall, &to->si_syscall);
130                         err |= __put_user(from->si_arch, &to->si_arch);
131                         break;
132                 }
133         }
134         return err;
135 }
136
137 int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
138 {
139         if (copy_from_user(to, from, 3*sizeof(int)) ||
140             copy_from_user(to->_sifields._pad,
141                            from->_sifields._pad, SI_PAD_SIZE32))
142                 return -EFAULT;
143
144         return 0;
145 }