xref: /openbmc/linux/arch/mips/kernel/signal32.c (revision d1e63c947a6fa4f61253343d9bbd834394a6c364)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * This file is subject to the terms and conditions of the GNU General Public
31da177e4SLinus Torvalds  * License.  See the file "COPYING" in the main directory of this archive
41da177e4SLinus Torvalds  * for more details.
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * Copyright (C) 1991, 1992  Linus Torvalds
7dda73d0bSMartin Michlmayr  * Copyright (C) 1994 - 2000, 2006  Ralf Baechle
81da177e4SLinus Torvalds  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
9*d1e63c94SHarvey Hunt  * Copyright (C) 2016, Imagination Technologies Ltd.
101da177e4SLinus Torvalds  */
11*d1e63c94SHarvey Hunt #include <linux/compiler.h>
12*d1e63c94SHarvey Hunt #include <linux/errno.h>
131da177e4SLinus Torvalds #include <linux/kernel.h>
141da177e4SLinus Torvalds #include <linux/signal.h>
151da177e4SLinus Torvalds #include <linux/syscalls.h>
161da177e4SLinus Torvalds 
17*d1e63c94SHarvey Hunt #include <asm/compat.h>
18431dc804SRalf Baechle #include <asm/compat-signal.h>
19*d1e63c94SHarvey Hunt #include <asm/uaccess.h>
20*d1e63c94SHarvey Hunt #include <asm/unistd.h>
211da177e4SLinus Torvalds 
2236a1f2c2SFranck Bui-Huu #include "signal-common.h"
2336a1f2c2SFranck Bui-Huu 
241da177e4SLinus Torvalds /* 32-bit compatibility types */
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds typedef unsigned int __sighandler32_t;
271da177e4SLinus Torvalds typedef void (*vfptr_t)(void);
281da177e4SLinus Torvalds 
299432a9baSFranck Bui-Huu /*
301da177e4SLinus Torvalds  * Atomically swap in the new signal mask, and wait for a signal.
311da177e4SLinus Torvalds  */
321da177e4SLinus Torvalds 
331910f4abSAl Viro asmlinkage int sys32_sigsuspend(compat_sigset_t __user *uset)
341da177e4SLinus Torvalds {
351910f4abSAl Viro 	return compat_sys_rt_sigsuspend(uset, sizeof(compat_sigset_t));
361da177e4SLinus Torvalds }
371da177e4SLinus Torvalds 
38aa584802SAl Viro SYSCALL_DEFINE3(32_sigaction, long, sig, const struct compat_sigaction __user *, act,
39aa584802SAl Viro 	struct compat_sigaction __user *, oact)
401da177e4SLinus Torvalds {
411da177e4SLinus Torvalds 	struct k_sigaction new_ka, old_ka;
421da177e4SLinus Torvalds 	int ret;
431da177e4SLinus Torvalds 	int err = 0;
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds 	if (act) {
461da177e4SLinus Torvalds 		old_sigset_t mask;
4777c728c2SRalf Baechle 		s32 handler;
481da177e4SLinus Torvalds 
491da177e4SLinus Torvalds 		if (!access_ok(VERIFY_READ, act, sizeof(*act)))
501da177e4SLinus Torvalds 			return -EFAULT;
5177c728c2SRalf Baechle 		err |= __get_user(handler, &act->sa_handler);
529bbf28a3SAtsushi Nemoto 		new_ka.sa.sa_handler = (void __user *)(s64)handler;
531da177e4SLinus Torvalds 		err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
541da177e4SLinus Torvalds 		err |= __get_user(mask, &act->sa_mask.sig[0]);
551da177e4SLinus Torvalds 		if (err)
561da177e4SLinus Torvalds 			return -EFAULT;
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds 		siginitset(&new_ka.sa.sa_mask, mask);
591da177e4SLinus Torvalds 	}
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds 	if (!ret && oact) {
641da177e4SLinus Torvalds 		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
651da177e4SLinus Torvalds 			return -EFAULT;
661da177e4SLinus Torvalds 		err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
671da177e4SLinus Torvalds 		err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
681da177e4SLinus Torvalds 				  &oact->sa_handler);
691da177e4SLinus Torvalds 		err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
701da177e4SLinus Torvalds 		err |= __put_user(0, &oact->sa_mask.sig[1]);
711da177e4SLinus Torvalds 		err |= __put_user(0, &oact->sa_mask.sig[2]);
721da177e4SLinus Torvalds 		err |= __put_user(0, &oact->sa_mask.sig[3]);
731da177e4SLinus Torvalds 		if (err)
741da177e4SLinus Torvalds 			return -EFAULT;
751da177e4SLinus Torvalds 	}
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds 	return ret;
781da177e4SLinus Torvalds }
791da177e4SLinus Torvalds 
80ce395960SAl Viro int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
811da177e4SLinus Torvalds {
821da177e4SLinus Torvalds 	int err;
831da177e4SLinus Torvalds 
841da177e4SLinus Torvalds 	if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
851da177e4SLinus Torvalds 		return -EFAULT;
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds 	/* If you change siginfo_t structure, please be sure
881da177e4SLinus Torvalds 	   this code is fixed accordingly.
891da177e4SLinus Torvalds 	   It should never copy any pad contained in the structure
901da177e4SLinus Torvalds 	   to avoid security leaks, but must copy the generic
911da177e4SLinus Torvalds 	   3 ints plus the relevant union member.
921da177e4SLinus Torvalds 	   This routine must convert siginfo from 64bit to 32bit as well
931da177e4SLinus Torvalds 	   at the same time.  */
941da177e4SLinus Torvalds 	err = __put_user(from->si_signo, &to->si_signo);
951da177e4SLinus Torvalds 	err |= __put_user(from->si_errno, &to->si_errno);
961da177e4SLinus Torvalds 	err |= __put_user((short)from->si_code, &to->si_code);
971da177e4SLinus Torvalds 	if (from->si_code < 0)
981da177e4SLinus Torvalds 		err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
991da177e4SLinus Torvalds 	else {
1001da177e4SLinus Torvalds 		switch (from->si_code >> 16) {
101a982099cSRalf Baechle 		case __SI_TIMER >> 16:
102a982099cSRalf Baechle 			err |= __put_user(from->si_tid, &to->si_tid);
103a982099cSRalf Baechle 			err |= __put_user(from->si_overrun, &to->si_overrun);
104a982099cSRalf Baechle 			err |= __put_user(from->si_int, &to->si_int);
105a982099cSRalf Baechle 			break;
1061da177e4SLinus Torvalds 		case __SI_CHLD >> 16:
1071da177e4SLinus Torvalds 			err |= __put_user(from->si_utime, &to->si_utime);
1081da177e4SLinus Torvalds 			err |= __put_user(from->si_stime, &to->si_stime);
1091da177e4SLinus Torvalds 			err |= __put_user(from->si_status, &to->si_status);
1101da177e4SLinus Torvalds 		default:
1111da177e4SLinus Torvalds 			err |= __put_user(from->si_pid, &to->si_pid);
1121da177e4SLinus Torvalds 			err |= __put_user(from->si_uid, &to->si_uid);
1131da177e4SLinus Torvalds 			break;
1141da177e4SLinus Torvalds 		case __SI_FAULT >> 16:
1155665a0acSAtsushi Nemoto 			err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
1161da177e4SLinus Torvalds 			break;
1171da177e4SLinus Torvalds 		case __SI_POLL >> 16:
1181da177e4SLinus Torvalds 			err |= __put_user(from->si_band, &to->si_band);
1191da177e4SLinus Torvalds 			err |= __put_user(from->si_fd, &to->si_fd);
1201da177e4SLinus Torvalds 			break;
1211da177e4SLinus Torvalds 		case __SI_RT >> 16: /* This is not generated by the kernel as of now.  */
1221da177e4SLinus Torvalds 		case __SI_MESGQ >> 16:
1231da177e4SLinus Torvalds 			err |= __put_user(from->si_pid, &to->si_pid);
1241da177e4SLinus Torvalds 			err |= __put_user(from->si_uid, &to->si_uid);
1251da177e4SLinus Torvalds 			err |= __put_user(from->si_int, &to->si_int);
1261da177e4SLinus Torvalds 			break;
1275050e91fSMatt Redfearn 		case __SI_SYS >> 16:
1285050e91fSMatt Redfearn 			err |= __copy_to_user(&to->si_call_addr, &from->si_call_addr,
1295050e91fSMatt Redfearn 					      sizeof(compat_uptr_t));
1305050e91fSMatt Redfearn 			err |= __put_user(from->si_syscall, &to->si_syscall);
1315050e91fSMatt Redfearn 			err |= __put_user(from->si_arch, &to->si_arch);
1325050e91fSMatt Redfearn 			break;
1331da177e4SLinus Torvalds 		}
1341da177e4SLinus Torvalds 	}
1351da177e4SLinus Torvalds 	return err;
1361da177e4SLinus Torvalds }
1371da177e4SLinus Torvalds 
1385d9a76cdSThomas Bogendoerfer int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
1395d9a76cdSThomas Bogendoerfer {
1405d9a76cdSThomas Bogendoerfer 	if (copy_from_user(to, from, 3*sizeof(int)) ||
1415d9a76cdSThomas Bogendoerfer 	    copy_from_user(to->_sifields._pad,
1425d9a76cdSThomas Bogendoerfer 			   from->_sifields._pad, SI_PAD_SIZE32))
1435d9a76cdSThomas Bogendoerfer 		return -EFAULT;
1445d9a76cdSThomas Bogendoerfer 
1455d9a76cdSThomas Bogendoerfer 	return 0;
1465d9a76cdSThomas Bogendoerfer }
147