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