Path: blob/master/arch/s390/kernel/compat_signal.c
10817 views
/*1* arch/s390/kernel/compat_signal.c2*3* Copyright (C) IBM Corp. 2000,20064* Author(s): Denis Joseph Barrow ([email protected],[email protected])5* Gerhard Tonn ([email protected])6*7* Copyright (C) 1991, 1992 Linus Torvalds8*9* 1997-11-28 Modified for POSIX.1b signals by Richard Henderson10*/1112#include <linux/compat.h>13#include <linux/sched.h>14#include <linux/mm.h>15#include <linux/smp.h>16#include <linux/kernel.h>17#include <linux/signal.h>18#include <linux/errno.h>19#include <linux/wait.h>20#include <linux/ptrace.h>21#include <linux/unistd.h>22#include <linux/stddef.h>23#include <linux/tty.h>24#include <linux/personality.h>25#include <linux/binfmts.h>26#include <asm/ucontext.h>27#include <asm/uaccess.h>28#include <asm/lowcore.h>29#include "compat_linux.h"30#include "compat_ptrace.h"31#include "entry.h"3233#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))3435typedef struct36{37__u8 callee_used_stack[__SIGNAL_FRAMESIZE32];38struct sigcontext32 sc;39_sigregs32 sregs;40int signo;41__u32 gprs_high[NUM_GPRS];42__u8 retcode[S390_SYSCALL_SIZE];43} sigframe32;4445typedef struct46{47__u8 callee_used_stack[__SIGNAL_FRAMESIZE32];48__u8 retcode[S390_SYSCALL_SIZE];49compat_siginfo_t info;50struct ucontext32 uc;51__u32 gprs_high[NUM_GPRS];52} rt_sigframe32;5354int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)55{56int err;5758if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))59return -EFAULT;6061/* If you change siginfo_t structure, please be sure62this code is fixed accordingly.63It should never copy any pad contained in the structure64to avoid security leaks, but must copy the generic653 ints plus the relevant union member.66This routine must convert siginfo from 64bit to 32bit as well67at the same time. */68err = __put_user(from->si_signo, &to->si_signo);69err |= __put_user(from->si_errno, &to->si_errno);70err |= __put_user((short)from->si_code, &to->si_code);71if (from->si_code < 0)72err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);73else {74switch (from->si_code >> 16) {75case __SI_RT >> 16: /* This is not generated by the kernel as of now. */76case __SI_MESGQ >> 16:77err |= __put_user(from->si_int, &to->si_int);78/* fallthrough */79case __SI_KILL >> 16:80err |= __put_user(from->si_pid, &to->si_pid);81err |= __put_user(from->si_uid, &to->si_uid);82break;83case __SI_CHLD >> 16:84err |= __put_user(from->si_pid, &to->si_pid);85err |= __put_user(from->si_uid, &to->si_uid);86err |= __put_user(from->si_utime, &to->si_utime);87err |= __put_user(from->si_stime, &to->si_stime);88err |= __put_user(from->si_status, &to->si_status);89break;90case __SI_FAULT >> 16:91err |= __put_user((unsigned long) from->si_addr,92&to->si_addr);93break;94case __SI_POLL >> 16:95err |= __put_user(from->si_band, &to->si_band);96err |= __put_user(from->si_fd, &to->si_fd);97break;98case __SI_TIMER >> 16:99err |= __put_user(from->si_tid, &to->si_tid);100err |= __put_user(from->si_overrun, &to->si_overrun);101err |= __put_user(from->si_int, &to->si_int);102break;103default:104break;105}106}107return err;108}109110int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)111{112int err;113u32 tmp;114115if (!access_ok (VERIFY_READ, from, sizeof(compat_siginfo_t)))116return -EFAULT;117118err = __get_user(to->si_signo, &from->si_signo);119err |= __get_user(to->si_errno, &from->si_errno);120err |= __get_user(to->si_code, &from->si_code);121122if (to->si_code < 0)123err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);124else {125switch (to->si_code >> 16) {126case __SI_RT >> 16: /* This is not generated by the kernel as of now. */127case __SI_MESGQ >> 16:128err |= __get_user(to->si_int, &from->si_int);129/* fallthrough */130case __SI_KILL >> 16:131err |= __get_user(to->si_pid, &from->si_pid);132err |= __get_user(to->si_uid, &from->si_uid);133break;134case __SI_CHLD >> 16:135err |= __get_user(to->si_pid, &from->si_pid);136err |= __get_user(to->si_uid, &from->si_uid);137err |= __get_user(to->si_utime, &from->si_utime);138err |= __get_user(to->si_stime, &from->si_stime);139err |= __get_user(to->si_status, &from->si_status);140break;141case __SI_FAULT >> 16:142err |= __get_user(tmp, &from->si_addr);143to->si_addr = (void __user *)(u64) (tmp & PSW32_ADDR_INSN);144break;145case __SI_POLL >> 16:146err |= __get_user(to->si_band, &from->si_band);147err |= __get_user(to->si_fd, &from->si_fd);148break;149case __SI_TIMER >> 16:150err |= __get_user(to->si_tid, &from->si_tid);151err |= __get_user(to->si_overrun, &from->si_overrun);152err |= __get_user(to->si_int, &from->si_int);153break;154default:155break;156}157}158return err;159}160161asmlinkage long162sys32_sigaction(int sig, const struct old_sigaction32 __user *act,163struct old_sigaction32 __user *oact)164{165struct k_sigaction new_ka, old_ka;166unsigned long sa_handler, sa_restorer;167int ret;168169if (act) {170compat_old_sigset_t mask;171if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||172__get_user(sa_handler, &act->sa_handler) ||173__get_user(sa_restorer, &act->sa_restorer) ||174__get_user(new_ka.sa.sa_flags, &act->sa_flags) ||175__get_user(mask, &act->sa_mask))176return -EFAULT;177new_ka.sa.sa_handler = (__sighandler_t) sa_handler;178new_ka.sa.sa_restorer = (void (*)(void)) sa_restorer;179siginitset(&new_ka.sa.sa_mask, mask);180}181182ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);183184if (!ret && oact) {185sa_handler = (unsigned long) old_ka.sa.sa_handler;186sa_restorer = (unsigned long) old_ka.sa.sa_restorer;187if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||188__put_user(sa_handler, &oact->sa_handler) ||189__put_user(sa_restorer, &oact->sa_restorer) ||190__put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||191__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))192return -EFAULT;193}194195return ret;196}197198asmlinkage long199sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,200struct sigaction32 __user *oact, size_t sigsetsize)201{202struct k_sigaction new_ka, old_ka;203unsigned long sa_handler;204int ret;205compat_sigset_t set32;206207/* XXX: Don't preclude handling different sized sigset_t's. */208if (sigsetsize != sizeof(compat_sigset_t))209return -EINVAL;210211if (act) {212ret = get_user(sa_handler, &act->sa_handler);213ret |= __copy_from_user(&set32, &act->sa_mask,214sizeof(compat_sigset_t));215switch (_NSIG_WORDS) {216case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6]217| (((long)set32.sig[7]) << 32);218case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4]219| (((long)set32.sig[5]) << 32);220case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2]221| (((long)set32.sig[3]) << 32);222case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0]223| (((long)set32.sig[1]) << 32);224}225ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);226227if (ret)228return -EFAULT;229new_ka.sa.sa_handler = (__sighandler_t) sa_handler;230}231232ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);233234if (!ret && oact) {235switch (_NSIG_WORDS) {236case 4:237set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32);238set32.sig[6] = old_ka.sa.sa_mask.sig[3];239case 3:240set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32);241set32.sig[4] = old_ka.sa.sa_mask.sig[2];242case 2:243set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32);244set32.sig[2] = old_ka.sa.sa_mask.sig[1];245case 1:246set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);247set32.sig[0] = old_ka.sa.sa_mask.sig[0];248}249ret = put_user((unsigned long)old_ka.sa.sa_handler, &oact->sa_handler);250ret |= __copy_to_user(&oact->sa_mask, &set32,251sizeof(compat_sigset_t));252ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);253}254255return ret;256}257258asmlinkage long259sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss)260{261struct pt_regs *regs = task_pt_regs(current);262stack_t kss, koss;263unsigned long ss_sp;264int ret, err = 0;265mm_segment_t old_fs = get_fs();266267if (uss) {268if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))269return -EFAULT;270err |= __get_user(ss_sp, &uss->ss_sp);271err |= __get_user(kss.ss_size, &uss->ss_size);272err |= __get_user(kss.ss_flags, &uss->ss_flags);273if (err)274return -EFAULT;275kss.ss_sp = (void __user *) ss_sp;276}277278set_fs (KERNEL_DS);279ret = do_sigaltstack((stack_t __force __user *) (uss ? &kss : NULL),280(stack_t __force __user *) (uoss ? &koss : NULL),281regs->gprs[15]);282set_fs (old_fs);283284if (!ret && uoss) {285if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))286return -EFAULT;287ss_sp = (unsigned long) koss.ss_sp;288err |= __put_user(ss_sp, &uoss->ss_sp);289err |= __put_user(koss.ss_size, &uoss->ss_size);290err |= __put_user(koss.ss_flags, &uoss->ss_flags);291if (err)292return -EFAULT;293}294return ret;295}296297static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)298{299_s390_regs_common32 regs32;300int err, i;301302regs32.psw.mask = PSW32_MASK_MERGE(psw32_user_bits,303(__u32)(regs->psw.mask >> 32));304regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr;305for (i = 0; i < NUM_GPRS; i++)306regs32.gprs[i] = (__u32) regs->gprs[i];307save_access_regs(current->thread.acrs);308memcpy(regs32.acrs, current->thread.acrs, sizeof(regs32.acrs));309err = __copy_to_user(&sregs->regs, ®s32, sizeof(regs32));310if (err)311return err;312save_fp_regs(¤t->thread.fp_regs);313/* s390_fp_regs and _s390_fp_regs32 are the same ! */314return __copy_to_user(&sregs->fpregs, ¤t->thread.fp_regs,315sizeof(_s390_fp_regs32));316}317318static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)319{320_s390_regs_common32 regs32;321int err, i;322323/* Alwys make any pending restarted system call return -EINTR */324current_thread_info()->restart_block.fn = do_no_restart_syscall;325326err = __copy_from_user(®s32, &sregs->regs, sizeof(regs32));327if (err)328return err;329regs->psw.mask = PSW_MASK_MERGE(regs->psw.mask,330(__u64)regs32.psw.mask << 32);331regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN);332for (i = 0; i < NUM_GPRS; i++)333regs->gprs[i] = (__u64) regs32.gprs[i];334memcpy(current->thread.acrs, regs32.acrs, sizeof(current->thread.acrs));335restore_access_regs(current->thread.acrs);336337err = __copy_from_user(¤t->thread.fp_regs, &sregs->fpregs,338sizeof(_s390_fp_regs32));339current->thread.fp_regs.fpc &= FPC_VALID_MASK;340if (err)341return err;342343restore_fp_regs(¤t->thread.fp_regs);344regs->svcnr = 0; /* disable syscall checks */345return 0;346}347348static int save_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)349{350__u32 gprs_high[NUM_GPRS];351int i;352353for (i = 0; i < NUM_GPRS; i++)354gprs_high[i] = regs->gprs[i] >> 32;355356return __copy_to_user(uregs, &gprs_high, sizeof(gprs_high));357}358359static int restore_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)360{361__u32 gprs_high[NUM_GPRS];362int err, i;363364err = __copy_from_user(&gprs_high, uregs, sizeof(gprs_high));365if (err)366return err;367for (i = 0; i < NUM_GPRS; i++)368*(__u32 *)®s->gprs[i] = gprs_high[i];369return 0;370}371372asmlinkage long sys32_sigreturn(void)373{374struct pt_regs *regs = task_pt_regs(current);375sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15];376sigset_t set;377378if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))379goto badframe;380if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32))381goto badframe;382383sigdelsetmask(&set, ~_BLOCKABLE);384spin_lock_irq(¤t->sighand->siglock);385current->blocked = set;386recalc_sigpending();387spin_unlock_irq(¤t->sighand->siglock);388389if (restore_sigregs32(regs, &frame->sregs))390goto badframe;391if (restore_sigregs_gprs_high(regs, frame->gprs_high))392goto badframe;393394return regs->gprs[2];395396badframe:397force_sig(SIGSEGV, current);398return 0;399}400401asmlinkage long sys32_rt_sigreturn(void)402{403struct pt_regs *regs = task_pt_regs(current);404rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15];405sigset_t set;406stack_t st;407__u32 ss_sp;408int err;409mm_segment_t old_fs = get_fs();410411if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))412goto badframe;413if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))414goto badframe;415416sigdelsetmask(&set, ~_BLOCKABLE);417spin_lock_irq(¤t->sighand->siglock);418current->blocked = set;419recalc_sigpending();420spin_unlock_irq(¤t->sighand->siglock);421422if (restore_sigregs32(regs, &frame->uc.uc_mcontext))423goto badframe;424if (restore_sigregs_gprs_high(regs, frame->gprs_high))425goto badframe;426427err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp);428st.ss_sp = compat_ptr(ss_sp);429err |= __get_user(st.ss_size, &frame->uc.uc_stack.ss_size);430err |= __get_user(st.ss_flags, &frame->uc.uc_stack.ss_flags);431if (err)432goto badframe;433434set_fs (KERNEL_DS);435do_sigaltstack((stack_t __force __user *)&st, NULL, regs->gprs[15]);436set_fs (old_fs);437438return regs->gprs[2];439440badframe:441force_sig(SIGSEGV, current);442return 0;443}444445/*446* Set up a signal frame.447*/448449450/*451* Determine which stack to use..452*/453static inline void __user *454get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)455{456unsigned long sp;457458/* Default to using normal stack */459sp = (unsigned long) A(regs->gprs[15]);460461/* Overflow on alternate signal stack gives SIGSEGV. */462if (on_sig_stack(sp) && !on_sig_stack((sp - frame_size) & -8UL))463return (void __user *) -1UL;464465/* This is the X/Open sanctioned signal stack switching. */466if (ka->sa.sa_flags & SA_ONSTACK) {467if (! sas_ss_flags(sp))468sp = current->sas_ss_sp + current->sas_ss_size;469}470471/* This is the legacy signal stack switching. */472else if (!user_mode(regs) &&473!(ka->sa.sa_flags & SA_RESTORER) &&474ka->sa.sa_restorer) {475sp = (unsigned long) ka->sa.sa_restorer;476}477478return (void __user *)((sp - frame_size) & -8ul);479}480481static inline int map_signal(int sig)482{483if (current_thread_info()->exec_domain484&& current_thread_info()->exec_domain->signal_invmap485&& sig < 32)486return current_thread_info()->exec_domain->signal_invmap[sig];487else488return sig;489}490491static int setup_frame32(int sig, struct k_sigaction *ka,492sigset_t *set, struct pt_regs * regs)493{494sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(sigframe32));495if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe32)))496goto give_sigsegv;497498if (frame == (void __user *) -1UL)499goto give_sigsegv;500501if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE32))502goto give_sigsegv;503504if (save_sigregs32(regs, &frame->sregs))505goto give_sigsegv;506if (save_sigregs_gprs_high(regs, frame->gprs_high))507goto give_sigsegv;508if (__put_user((unsigned long) &frame->sregs, &frame->sc.sregs))509goto give_sigsegv;510511/* Set up to return from userspace. If provided, use a stub512already in userspace. */513if (ka->sa.sa_flags & SA_RESTORER) {514regs->gprs[14] = (__u64) ka->sa.sa_restorer;515} else {516regs->gprs[14] = (__u64) frame->retcode;517if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,518(u16 __user *)(frame->retcode)))519goto give_sigsegv;520}521522/* Set up backchain. */523if (__put_user(regs->gprs[15], (unsigned int __user *) frame))524goto give_sigsegv;525526/* Set up registers for signal handler */527regs->gprs[15] = (__u64) frame;528regs->psw.addr = (__u64) ka->sa.sa_handler;529530regs->gprs[2] = map_signal(sig);531regs->gprs[3] = (__u64) &frame->sc;532533/* We forgot to include these in the sigcontext.534To avoid breaking binary compatibility, they are passed as args. */535regs->gprs[4] = current->thread.trap_no;536regs->gprs[5] = current->thread.prot_addr;537538/* Place signal number on stack to allow backtrace from handler. */539if (__put_user(regs->gprs[2], (int __user *) &frame->signo))540goto give_sigsegv;541return 0;542543give_sigsegv:544force_sigsegv(sig, current);545return -EFAULT;546}547548static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,549sigset_t *set, struct pt_regs * regs)550{551int err = 0;552rt_sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32));553if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe32)))554goto give_sigsegv;555556if (frame == (void __user *) -1UL)557goto give_sigsegv;558559if (copy_siginfo_to_user32(&frame->info, info))560goto give_sigsegv;561562/* Create the ucontext. */563err |= __put_user(UC_EXTENDED, &frame->uc.uc_flags);564err |= __put_user(0, &frame->uc.uc_link);565err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);566err |= __put_user(sas_ss_flags(regs->gprs[15]),567&frame->uc.uc_stack.ss_flags);568err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);569err |= save_sigregs32(regs, &frame->uc.uc_mcontext);570err |= save_sigregs_gprs_high(regs, frame->gprs_high);571err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));572if (err)573goto give_sigsegv;574575/* Set up to return from userspace. If provided, use a stub576already in userspace. */577if (ka->sa.sa_flags & SA_RESTORER) {578regs->gprs[14] = (__u64) ka->sa.sa_restorer;579} else {580regs->gprs[14] = (__u64) frame->retcode;581err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,582(u16 __user *)(frame->retcode));583}584585/* Set up backchain. */586if (__put_user(regs->gprs[15], (unsigned int __user *) frame))587goto give_sigsegv;588589/* Set up registers for signal handler */590regs->gprs[15] = (__u64) frame;591regs->psw.addr = (__u64) ka->sa.sa_handler;592593regs->gprs[2] = map_signal(sig);594regs->gprs[3] = (__u64) &frame->info;595regs->gprs[4] = (__u64) &frame->uc;596return 0;597598give_sigsegv:599force_sigsegv(sig, current);600return -EFAULT;601}602603/*604* OK, we're invoking a handler605*/606607int608handle_signal32(unsigned long sig, struct k_sigaction *ka,609siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)610{611int ret;612613/* Set up the stack frame */614if (ka->sa.sa_flags & SA_SIGINFO)615ret = setup_rt_frame32(sig, ka, info, oldset, regs);616else617ret = setup_frame32(sig, ka, oldset, regs);618619if (ret == 0) {620spin_lock_irq(¤t->sighand->siglock);621sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);622if (!(ka->sa.sa_flags & SA_NODEFER))623sigaddset(¤t->blocked,sig);624recalc_sigpending();625spin_unlock_irq(¤t->sighand->siglock);626}627return ret;628}629630631632