compat_signal.c revision e214125aa8c0546b24dabf6f47b28c5e20133d1d
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2a53c8fab3f87c995c30ac226a03af95361243144Heiko Carstens *    Copyright IBM Corp. 2000, 2006
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *               Gerhard Tonn (ton@de.ibm.com)
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 1991, 1992  Linus Torvalds
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/compat.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/smp.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/signal.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/wait.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/unistd.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/stddef.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/personality.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/binfmts.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/ucontext.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/lowcore.h>
28a0616cdebcfd575dcd4c46102d1b52fbb827fc29David Howells#include <asm/switch_to.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "compat_linux.h"
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "compat_ptrace.h"
31a806170e29c5468b1d641a22518243bdf1b8d58bHeiko Carstens#include "entry.h"
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sigcontext32 sc;
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_sigregs32 sregs;
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int signo;
39ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	__u32 gprs_high[NUM_GPRS];
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 retcode[S390_SYSCALL_SIZE];
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} sigframe32;
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 retcode[S390_SYSCALL_SIZE];
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	compat_siginfo_t info;
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ucontext32 uc;
49ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	__u32 gprs_high[NUM_GPRS];
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} rt_sigframe32;
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If you change siginfo_t structure, please be sure
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   this code is fixed accordingly.
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   It should never copy any pad contained in the structure
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   to avoid security leaks, but must copy the generic
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   3 ints plus the relevant union member.
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   This routine must convert siginfo from 64bit to 32bit as well
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   at the same time.  */
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = __put_user(from->si_signo, &to->si_signo);
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err |= __put_user(from->si_errno, &to->si_errno);
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err |= __put_user((short)from->si_code, &to->si_code);
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (from->si_code < 0)
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else {
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (from->si_code >> 16) {
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_RT >> 16: /* This is not generated by the kernel as of now.  */
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_MESGQ >> 16:
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_int, &to->si_int);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* fallthrough */
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_KILL >> 16:
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_pid, &to->si_pid);
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_uid, &to->si_uid);
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_CHLD >> 16:
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_pid, &to->si_pid);
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_uid, &to->si_uid);
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_utime, &to->si_utime);
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_stime, &to->si_stime);
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_status, &to->si_status);
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_FAULT >> 16:
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user((unsigned long) from->si_addr,
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  &to->si_addr);
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_POLL >> 16:
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_band, &to->si_band);
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_fd, &to->si_fd);
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_TIMER >> 16:
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_tid, &to->si_tid);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_overrun, &to->si_overrun);
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_int, &to->si_int);
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 tmp;
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!access_ok (VERIFY_READ, from, sizeof(compat_siginfo_t)))
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = __get_user(to->si_signo, &from->si_signo);
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err |= __get_user(to->si_errno, &from->si_errno);
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err |= __get_user(to->si_code, &from->si_code);
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (to->si_code < 0)
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else {
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (to->si_code >> 16) {
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_RT >> 16: /* This is not generated by the kernel as of now.  */
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_MESGQ >> 16:
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_int, &from->si_int);
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* fallthrough */
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_KILL >> 16:
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_pid, &from->si_pid);
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_uid, &from->si_uid);
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_CHLD >> 16:
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_pid, &from->si_pid);
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_uid, &from->si_uid);
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_utime, &from->si_utime);
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_stime, &from->si_stime);
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_status, &from->si_status);
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_FAULT >> 16:
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(tmp, &from->si_addr);
1413c52e49d7c81434e3d2ccb520b3a654c2cc7d03dMartin Schwidefsky			to->si_addr = (void __force __user *)
1423c52e49d7c81434e3d2ccb520b3a654c2cc7d03dMartin Schwidefsky				(u64) (tmp & PSW32_ADDR_INSN);
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_POLL >> 16:
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_band, &from->si_band);
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_fd, &from->si_fd);
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_TIMER >> 16:
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_tid, &from->si_tid);
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_overrun, &from->si_overrun);
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_int, &from->si_int);
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasmlinkage long
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssys32_sigaction(int sig, const struct old_sigaction32 __user *act,
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 struct old_sigaction32 __user *oact)
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        struct k_sigaction new_ka, old_ka;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long sa_handler, sa_restorer;
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        int ret;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (act) {
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		compat_old_sigset_t mask;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    __get_user(sa_handler, &act->sa_handler) ||
17212bae23507129a7337378e6433bff6f8696bdb45Heiko Carstens		    __get_user(sa_restorer, &act->sa_restorer) ||
17312bae23507129a7337378e6433bff6f8696bdb45Heiko Carstens		    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
17412bae23507129a7337378e6433bff6f8696bdb45Heiko Carstens		    __get_user(mask, &act->sa_mask))
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new_ka.sa.sa_handler = (__sighandler_t) sa_handler;
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new_ka.sa.sa_restorer = (void (*)(void)) sa_restorer;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		siginitset(&new_ka.sa.sa_mask, mask);
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ret && oact) {
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sa_handler = (unsigned long) old_ka.sa.sa_handler;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sa_restorer = (unsigned long) old_ka.sa.sa_restorer;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    __put_user(sa_handler, &oact->sa_handler) ||
18812bae23507129a7337378e6433bff6f8696bdb45Heiko Carstens		    __put_user(sa_restorer, &oact->sa_restorer) ||
18912bae23507129a7337378e6433bff6f8696bdb45Heiko Carstens		    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
19012bae23507129a7337378e6433bff6f8696bdb45Heiko Carstens		    __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasmlinkage long
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   struct sigaction32 __user *oact,  size_t sigsetsize)
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct k_sigaction new_ka, old_ka;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long sa_handler;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	compat_sigset_t set32;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* XXX: Don't preclude handling different sized sigset_t's.  */
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sigsetsize != sizeof(compat_sigset_t))
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (act) {
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = get_user(sa_handler, &act->sa_handler);
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret |= __copy_from_user(&set32, &act->sa_mask,
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					sizeof(compat_sigset_t));
214399c1d8dbfdcf46977fd2e2a833b02e18a284810Martin Schwidefsky		new_ka.sa.sa_mask.sig[0] =
215399c1d8dbfdcf46977fd2e2a833b02e18a284810Martin Schwidefsky			set32.sig[0] | (((long)set32.sig[1]) << 32);
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret)
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new_ka.sa.sa_handler = (__sighandler_t) sa_handler;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ret && oact) {
226399c1d8dbfdcf46977fd2e2a833b02e18a284810Martin Schwidefsky		set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);
227399c1d8dbfdcf46977fd2e2a833b02e18a284810Martin Schwidefsky		set32.sig[0] = old_ka.sa.sa_mask.sig[0];
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = put_user((unsigned long)old_ka.sa.sa_handler, &oact->sa_handler);
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret |= __copy_to_user(&oact->sa_mask, &set32,
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      sizeof(compat_sigset_t));
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_s390_regs_common32 regs32;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err, i;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
242b50511e41aa51a89b4176784a670582424bc7db6Martin Schwidefsky	regs32.psw.mask = psw32_user_bits |
243b50511e41aa51a89b4176784a670582424bc7db6Martin Schwidefsky		((__u32)(regs->psw.mask >> 32) & PSW32_MASK_USER);
244d4e81b35b882d96f059afdb0f98e5b6025973b09Martin Schwidefsky	regs32.psw.addr = (__u32) regs->psw.addr |
245d4e81b35b882d96f059afdb0f98e5b6025973b09Martin Schwidefsky		(__u32)(regs->psw.mask & PSW_MASK_BA);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < NUM_GPRS; i++)
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		regs32.gprs[i] = (__u32) regs->gprs[i];
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	save_access_regs(current->thread.acrs);
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(regs32.acrs, current->thread.acrs, sizeof(regs32.acrs));
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = __copy_to_user(&sregs->regs, &regs32, sizeof(regs32));
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	save_fp_regs(&current->thread.fp_regs);
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* s390_fp_regs and _s390_fp_regs32 are the same ! */
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return __copy_to_user(&sregs->fpregs, &current->thread.fp_regs,
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      sizeof(_s390_fp_regs32));
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_s390_regs_common32 regs32;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err, i;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Alwys make any pending restarted system call return -EINTR */
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current_thread_info()->restart_block.fn = do_no_restart_syscall;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = __copy_from_user(&regs32, &sregs->regs, sizeof(regs32));
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
270b50511e41aa51a89b4176784a670582424bc7db6Martin Schwidefsky	regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
271d4e81b35b882d96f059afdb0f98e5b6025973b09Martin Schwidefsky		(__u64)(regs32.psw.mask & PSW32_MASK_USER) << 32 |
272d4e81b35b882d96f059afdb0f98e5b6025973b09Martin Schwidefsky		(__u64)(regs32.psw.addr & PSW32_ADDR_AMODE);
273fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky	/* Check for invalid user address space control. */
274fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky	if ((regs->psw.mask & PSW_MASK_ASC) >= (psw_kernel_bits & PSW_MASK_ASC))
275fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky		regs->psw.mask = (psw_user_bits & PSW_MASK_ASC) |
276fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky			(regs->psw.mask & ~PSW_MASK_ASC);
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN);
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < NUM_GPRS; i++)
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		regs->gprs[i] = (__u64) regs32.gprs[i];
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(current->thread.acrs, regs32.acrs, sizeof(current->thread.acrs));
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	restore_access_regs(current->thread.acrs);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = __copy_from_user(&current->thread.fp_regs, &sregs->fpregs,
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       sizeof(_s390_fp_regs32));
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current->thread.fp_regs.fpc &= FPC_VALID_MASK;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	restore_fp_regs(&current->thread.fp_regs);
290b6ef5bb3d93efb95ba855a628740375c2280a59eMartin Schwidefsky	clear_thread_flag(TIF_SYSCALL);	/* No longer in a system call */
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
294ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstensstatic int save_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)
295ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens{
296ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	__u32 gprs_high[NUM_GPRS];
297ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	int i;
298ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens
299ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	for (i = 0; i < NUM_GPRS; i++)
300ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens		gprs_high[i] = regs->gprs[i] >> 32;
301ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens
302ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	return __copy_to_user(uregs, &gprs_high, sizeof(gprs_high));
303ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens}
304ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens
305ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstensstatic int restore_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)
306ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens{
307ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	__u32 gprs_high[NUM_GPRS];
308ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	int err, i;
309ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens
310ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	err = __copy_from_user(&gprs_high, uregs, sizeof(gprs_high));
311ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	if (err)
312ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens		return err;
313ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	for (i = 0; i < NUM_GPRS; i++)
314ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens		*(__u32 *)&regs->gprs[i] = gprs_high[i];
315ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	return 0;
316ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens}
317ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens
31803ff9a235a0602724fc54916469b6e0939c62c9bMartin Schwidefskyasmlinkage long sys32_sigreturn(void)
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
32003ff9a235a0602724fc54916469b6e0939c62c9bMartin Schwidefsky	struct pt_regs *regs = task_pt_regs(current);
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15];
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigset_t set;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto badframe;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32))
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto badframe;
328391c62feb1798b6d31bd88076eae649b091ad8bfHeiko Carstens	set_current_blocked(&set);
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (restore_sigregs32(regs, &frame->sregs))
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto badframe;
331ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	if (restore_sigregs_gprs_high(regs, frame->gprs_high))
332ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens		goto badframe;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return regs->gprs[2];
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsbadframe:
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	force_sig(SIGSEGV, current);
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33903ff9a235a0602724fc54916469b6e0939c62c9bMartin Schwidefskyasmlinkage long sys32_rt_sigreturn(void)
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
34103ff9a235a0602724fc54916469b6e0939c62c9bMartin Schwidefsky	struct pt_regs *regs = task_pt_regs(current);
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15];
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigset_t set;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto badframe;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto badframe;
349391c62feb1798b6d31bd88076eae649b091ad8bfHeiko Carstens	set_current_blocked(&set);
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto badframe;
352ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	if (restore_sigregs_gprs_high(regs, frame->gprs_high))
353ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens		goto badframe;
354e214125aa8c0546b24dabf6f47b28c5e20133d1dAl Viro	if (compat_restore_altstack(&frame->uc.uc_stack))
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto badframe;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return regs->gprs[2];
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsbadframe:
35803ff9a235a0602724fc54916469b6e0939c62c9bMartin Schwidefsky	force_sig(SIGSEGV, current);
35903ff9a235a0602724fc54916469b6e0939c62c9bMartin Schwidefsky	return 0;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set up a signal frame.
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Determine which stack to use..
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void __user *
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsget_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long sp;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Default to using normal stack */
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp = (unsigned long) A(regs->gprs[15]);
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
378de553438eb6c487f72d46019eb3821f6687ce011Heiko Carstens	/* Overflow on alternate signal stack gives SIGSEGV. */
379de553438eb6c487f72d46019eb3821f6687ce011Heiko Carstens	if (on_sig_stack(sp) && !on_sig_stack((sp - frame_size) & -8UL))
380de553438eb6c487f72d46019eb3821f6687ce011Heiko Carstens		return (void __user *) -1UL;
381de553438eb6c487f72d46019eb3821f6687ce011Heiko Carstens
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* This is the X/Open sanctioned signal stack switching.  */
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ka->sa.sa_flags & SA_ONSTACK) {
38428f223782bca914ae65d08234c57c2175ecd7f5dLaurent Meyer		if (! sas_ss_flags(sp))
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sp = current->sas_ss_sp + current->sas_ss_size;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (void __user *)((sp - frame_size) & -8ul);
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int map_signal(int sig)
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (current_thread_info()->exec_domain
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    && current_thread_info()->exec_domain->signal_invmap
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    && sig < 32)
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return current_thread_info()->exec_domain->signal_invmap[sig];
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        else
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return sig;
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40154dfe5dd9abc547f63060d132dad2c024a47de1eHeiko Carstensstatic int setup_frame32(int sig, struct k_sigaction *ka,
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sigset_t *set, struct pt_regs * regs)
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(sigframe32));
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe32)))
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto give_sigsegv;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
408de553438eb6c487f72d46019eb3821f6687ce011Heiko Carstens	if (frame == (void __user *) -1UL)
409de553438eb6c487f72d46019eb3821f6687ce011Heiko Carstens		goto give_sigsegv;
410de553438eb6c487f72d46019eb3821f6687ce011Heiko Carstens
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE32))
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto give_sigsegv;
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (save_sigregs32(regs, &frame->sregs))
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto give_sigsegv;
416ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	if (save_sigregs_gprs_high(regs, frame->gprs_high))
417ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens		goto give_sigsegv;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (__put_user((unsigned long) &frame->sregs, &frame->sc.sregs))
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto give_sigsegv;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set up to return from userspace.  If provided, use a stub
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   already in userspace.  */
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ka->sa.sa_flags & SA_RESTORER) {
424d4e81b35b882d96f059afdb0f98e5b6025973b09Martin Schwidefsky		regs->gprs[14] = (__u64) ka->sa.sa_restorer | PSW32_ADDR_AMODE;
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
426d4e81b35b882d96f059afdb0f98e5b6025973b09Martin Schwidefsky		regs->gprs[14] = (__u64) frame->retcode | PSW32_ADDR_AMODE;
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
4283c52e49d7c81434e3d2ccb520b3a654c2cc7d03dMartin Schwidefsky			       (u16 __force __user *)(frame->retcode)))
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto give_sigsegv;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set up backchain. */
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (__put_user(regs->gprs[15], (unsigned int __user *) frame))
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto give_sigsegv;
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set up registers for signal handler */
4373c52e49d7c81434e3d2ccb520b3a654c2cc7d03dMartin Schwidefsky	regs->gprs[15] = (__force __u64) frame;
438fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky	/* Force 31 bit amode and default user address space control. */
439fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky	regs->psw.mask = PSW_MASK_BA |
440fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky		(psw_user_bits & PSW_MASK_ASC) |
441fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky		(regs->psw.mask & ~PSW_MASK_ASC);
4423c52e49d7c81434e3d2ccb520b3a654c2cc7d03dMartin Schwidefsky	regs->psw.addr = (__force __u64) ka->sa.sa_handler;
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	regs->gprs[2] = map_signal(sig);
4453c52e49d7c81434e3d2ccb520b3a654c2cc7d03dMartin Schwidefsky	regs->gprs[3] = (__force __u64) &frame->sc;
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We forgot to include these in the sigcontext.
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   To avoid breaking binary compatibility, they are passed as args. */
449aa33c8cbbae2eb98489a3a363099b362146a8f4cMartin Schwidefsky	if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
450aa33c8cbbae2eb98489a3a363099b362146a8f4cMartin Schwidefsky	    sig == SIGTRAP || sig == SIGFPE) {
451aa33c8cbbae2eb98489a3a363099b362146a8f4cMartin Schwidefsky		/* set extra registers only for synchronous signals */
452aa33c8cbbae2eb98489a3a363099b362146a8f4cMartin Schwidefsky		regs->gprs[4] = regs->int_code & 127;
453aa33c8cbbae2eb98489a3a363099b362146a8f4cMartin Schwidefsky		regs->gprs[5] = regs->int_parm_long;
454aa33c8cbbae2eb98489a3a363099b362146a8f4cMartin Schwidefsky	}
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Place signal number on stack to allow backtrace from handler.  */
4573c52e49d7c81434e3d2ccb520b3a654c2cc7d03dMartin Schwidefsky	if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo))
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto give_sigsegv;
45954dfe5dd9abc547f63060d132dad2c024a47de1eHeiko Carstens	return 0;
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsgive_sigsegv:
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	force_sigsegv(sig, current);
46354dfe5dd9abc547f63060d132dad2c024a47de1eHeiko Carstens	return -EFAULT;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46654dfe5dd9abc547f63060d132dad2c024a47de1eHeiko Carstensstatic int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   sigset_t *set, struct pt_regs * regs)
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rt_sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32));
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe32)))
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto give_sigsegv;
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
474de553438eb6c487f72d46019eb3821f6687ce011Heiko Carstens	if (frame == (void __user *) -1UL)
475de553438eb6c487f72d46019eb3821f6687ce011Heiko Carstens		goto give_sigsegv;
476de553438eb6c487f72d46019eb3821f6687ce011Heiko Carstens
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_siginfo_to_user32(&frame->info, info))
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto give_sigsegv;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Create the ucontext.  */
481ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	err |= __put_user(UC_EXTENDED, &frame->uc.uc_flags);
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err |= __put_user(0, &frame->uc.uc_link);
483e214125aa8c0546b24dabf6f47b28c5e20133d1dAl Viro	err |= __compat_save_altstack(&frame->uc.uc_stack, regs->gprs[15]);
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err |= save_sigregs32(regs, &frame->uc.uc_mcontext);
485ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	err |= save_sigregs_gprs_high(regs, frame->gprs_high);
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto give_sigsegv;
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set up to return from userspace.  If provided, use a stub
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   already in userspace.  */
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ka->sa.sa_flags & SA_RESTORER) {
493207a05499bf11216ac96f76b38be728f4ee49304Martin Schwidefsky		regs->gprs[14] = (__u64) ka->sa.sa_restorer | PSW32_ADDR_AMODE;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
495207a05499bf11216ac96f76b38be728f4ee49304Martin Schwidefsky		regs->gprs[14] = (__u64) frame->retcode | PSW32_ADDR_AMODE;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
4973c52e49d7c81434e3d2ccb520b3a654c2cc7d03dMartin Schwidefsky				  (u16 __force __user *)(frame->retcode));
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set up backchain. */
5013c52e49d7c81434e3d2ccb520b3a654c2cc7d03dMartin Schwidefsky	if (__put_user(regs->gprs[15], (unsigned int __force __user *) frame))
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto give_sigsegv;
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set up registers for signal handler */
5053c52e49d7c81434e3d2ccb520b3a654c2cc7d03dMartin Schwidefsky	regs->gprs[15] = (__force __u64) frame;
506fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky	/* Force 31 bit amode and default user address space control. */
507fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky	regs->psw.mask = PSW_MASK_BA |
508fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky		(psw_user_bits & PSW_MASK_ASC) |
509fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky		(regs->psw.mask & ~PSW_MASK_ASC);
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	regs->psw.addr = (__u64) ka->sa.sa_handler;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	regs->gprs[2] = map_signal(sig);
5133c52e49d7c81434e3d2ccb520b3a654c2cc7d03dMartin Schwidefsky	regs->gprs[3] = (__force __u64) &frame->info;
5143c52e49d7c81434e3d2ccb520b3a654c2cc7d03dMartin Schwidefsky	regs->gprs[4] = (__force __u64) &frame->uc;
51554dfe5dd9abc547f63060d132dad2c024a47de1eHeiko Carstens	return 0;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsgive_sigsegv:
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	force_sigsegv(sig, current);
51954dfe5dd9abc547f63060d132dad2c024a47de1eHeiko Carstens	return -EFAULT;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * OK, we're invoking a handler
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
526a610d6e672d6d3723e8da257ad4a8a288a8f2f89Al Virovoid handle_signal32(unsigned long sig, struct k_sigaction *ka,
527391c62feb1798b6d31bd88076eae649b091ad8bfHeiko Carstens		    siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
52954dfe5dd9abc547f63060d132dad2c024a47de1eHeiko Carstens	int ret;
53054dfe5dd9abc547f63060d132dad2c024a47de1eHeiko Carstens
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set up the stack frame */
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ka->sa.sa_flags & SA_SIGINFO)
53354dfe5dd9abc547f63060d132dad2c024a47de1eHeiko Carstens		ret = setup_rt_frame32(sig, ka, info, oldset, regs);
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
53554dfe5dd9abc547f63060d132dad2c024a47de1eHeiko Carstens		ret = setup_frame32(sig, ka, oldset, regs);
536391c62feb1798b6d31bd88076eae649b091ad8bfHeiko Carstens	if (ret)
537a610d6e672d6d3723e8da257ad4a8a288a8f2f89Al Viro		return;
538efee984c27b67e3ebef40410f35671997441b57cAl Viro	signal_delivered(sig, info, ka, regs,
539a610d6e672d6d3723e8da257ad4a8a288a8f2f89Al Viro				 test_thread_flag(TIF_SINGLE_STEP));
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
542