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