xref: /openbmc/linux/arch/mips/kernel/signal32.c (revision b78412b8)
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 }
146