📄 ia32_signal.c
字号:
/* * IA32 Architecture-specific signal handling support. * * Copyright (C) 1999, 2001 Hewlett-Packard Co * David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com> * Copyright (C) 2000 VA Linux Co * Copyright (C) 2000 Don Dugger <n0ano@valinux.com> * * Derived from i386 and Alpha versions. */#include <linux/errno.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/personality.h>#include <linux/ptrace.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/stddef.h>#include <linux/unistd.h>#include <linux/wait.h>#include <asm/uaccess.h>#include <asm/rse.h>#include <asm/sigcontext.h>#include <asm/segment.h>#include <asm/ia32.h>#include "../kernel/sigframe.h"#define A(__x) ((unsigned long)(__x))#define DEBUG_SIG 0#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))#define __IA32_NR_sigreturn 119#define __IA32_NR_rt_sigreturn 173struct sigframe_ia32{ int pretcode; int sig; struct sigcontext_ia32 sc; struct _fpstate_ia32 fpstate; unsigned int extramask[_IA32_NSIG_WORDS-1]; char retcode[8];};struct rt_sigframe_ia32{ int pretcode; int sig; int pinfo; int puc; siginfo_t32 info; struct ucontext_ia32 uc; struct _fpstate_ia32 fpstate; char retcode[8];};intcopy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 *from){ unsigned long tmp; int err; if (!access_ok(VERIFY_READ, from, sizeof(siginfo_t32))) return -EFAULT; err = __get_user(to->si_signo, &from->si_signo); err |= __get_user(to->si_errno, &from->si_errno); err |= __get_user(to->si_code, &from->si_code); if (from->si_code < 0) err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); else { switch (from->si_code >> 16) { case __SI_CHLD >> 16: err |= __get_user(to->si_utime, &from->si_utime); err |= __get_user(to->si_stime, &from->si_stime); err |= __get_user(to->si_status, &from->si_status); default: err |= __get_user(to->si_pid, &from->si_pid); err |= __get_user(to->si_uid, &from->si_uid); break; case __SI_FAULT >> 16: err |= __get_user(tmp, &from->si_addr); to->si_addr = (void *) tmp; break; case __SI_POLL >> 16: err |= __get_user(to->si_band, &from->si_band); err |= __get_user(to->si_fd, &from->si_fd); break; /* case __SI_RT: This is not generated by the kernel as of now. */ } } return err;}intcopy_siginfo_to_user32 (siginfo_t32 *to, siginfo_t *from){ int err; if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t32))) return -EFAULT; /* If you change siginfo_t structure, please be sure this code is fixed accordingly. It should never copy any pad contained in the structure to avoid security leaks, but must copy the generic 3 ints plus the relevant union member. This routine must convert siginfo from 64bit to 32bit as well at the same time. */ err = __put_user(from->si_signo, &to->si_signo); err |= __put_user(from->si_errno, &to->si_errno); err |= __put_user((short)from->si_code, &to->si_code); if (from->si_code < 0) err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); else { switch (from->si_code >> 16) { case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_status, &to->si_status); default: err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_uid, &to->si_uid); break; case __SI_FAULT >> 16: err |= __put_user((long)from->si_addr, &to->si_addr); break; case __SI_POLL >> 16: err |= __put_user(from->si_band, &to->si_band); err |= __put_user(from->si_fd, &to->si_fd); break; /* case __SI_RT: This is not generated by the kernel as of now. */ } } return err;}static inline voidsigact_set_handler (struct k_sigaction *sa, unsigned int handler, unsigned int restorer){ if (handler + 1 <= 2) /* SIG_DFL, SIG_IGN, or SIG_ERR: must sign-extend to 64-bits */ sa->sa.sa_handler = (__sighandler_t) A((int) handler); else sa->sa.sa_handler = (__sighandler_t) (((unsigned long) restorer << 32) | handler);}asmlinkage longia32_rt_sigsuspend (sigset32_t *uset, unsigned int sigsetsize, struct sigscratch *scr){ extern long ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall); sigset_t oldset, set; scr->scratch_unat = 0; /* avoid leaking kernel bits to user level */ memset(&set, 0, sizeof(&set)); if (sigsetsize > sizeof(sigset_t)) return -EINVAL; if (copy_from_user(&set.sig, &uset->sig, sigsetsize)) return -EFAULT; sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sigmask_lock); { oldset = current->blocked; current->blocked = set; recalc_sigpending(current); } spin_unlock_irq(¤t->sigmask_lock); /* * The return below usually returns to the signal handler. We need to pre-set the * correct error code here to ensure that the right values get saved in sigcontext * by ia64_do_signal. */ scr->pt.r8 = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); if (ia64_do_signal(&oldset, scr, 1)) return -EINTR; }}asmlinkage longia32_sigsuspend (unsigned int mask, struct sigscratch *scr){ return ia32_rt_sigsuspend((sigset32_t *)&mask, sizeof(mask), scr);}asmlinkage longsys32_signal (int sig, unsigned int handler){ struct k_sigaction new_sa, old_sa; int ret; sigact_set_handler(&new_sa, handler, 0); new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK; ret = do_sigaction(sig, &new_sa, &old_sa); return ret ? ret : IA32_SA_HANDLER(&old_sa);}asmlinkage longsys32_rt_sigaction (int sig, struct sigaction32 *act, struct sigaction32 *oact, unsigned int sigsetsize){ struct k_sigaction new_ka, old_ka; unsigned int handler, restorer; int ret; /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(sigset32_t)) return -EINVAL; if (act) { ret = get_user(handler, &act->sa_handler); ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags); ret |= get_user(restorer, &act->sa_restorer); ret |= copy_from_user(&new_ka.sa.sa_mask, &act->sa_mask, sizeof(sigset32_t)); if (ret) return -EFAULT; sigact_set_handler(&new_ka, handler, restorer); } ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { ret = put_user(IA32_SA_HANDLER(&old_ka), &oact->sa_handler); ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags); ret |= put_user(IA32_SA_RESTORER(&old_ka), &oact->sa_restorer); ret |= copy_to_user(&oact->sa_mask, &old_ka.sa.sa_mask, sizeof(sigset32_t)); } return ret;}extern asmlinkage long sys_rt_sigprocmask (int how, sigset_t *set, sigset_t *oset, size_t sigsetsize);asmlinkage longsys32_rt_sigprocmask (int how, sigset32_t *set, sigset32_t *oset, unsigned int sigsetsize){ mm_segment_t old_fs = get_fs(); sigset_t s; long ret; if (sigsetsize > sizeof(s)) return -EINVAL; if (set) { memset(&s, 0, sizeof(s)); if (copy_from_user(&s.sig, set, sigsetsize)) return -EFAULT; } set_fs(KERNEL_DS); ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL, sizeof(s)); set_fs(old_fs); if (ret) return ret; if (oset) { if (copy_to_user(oset, &s.sig, sigsetsize)) return -EFAULT; } return 0;}asmlinkage longsys32_sigprocmask (int how, unsigned int *set, unsigned int *oset){ return sys32_rt_sigprocmask(how, (sigset32_t *) set, (sigset32_t *) oset, sizeof(*set));}asmlinkage longsys32_rt_sigtimedwait (sigset32_t *uthese, siginfo_t32 *uinfo, struct timespec32 *uts, unsigned int sigsetsize){ extern asmlinkage long sys_rt_sigtimedwait (const sigset_t *, siginfo_t *, const struct timespec *, size_t); extern int copy_siginfo_to_user32 (siginfo_t32 *, siginfo_t *); mm_segment_t old_fs = get_fs(); struct timespec t; siginfo_t info; sigset_t s; int ret; if (copy_from_user(&s.sig, uthese, sizeof(sigset32_t))) return -EFAULT; if (uts) { ret = get_user(t.tv_sec, &uts->tv_sec); ret |= get_user(t.tv_nsec, &uts->tv_nsec); if (ret) return -EFAULT; } set_fs(KERNEL_DS); ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize); set_fs(old_fs); if (ret >= 0 && uinfo) { if (copy_siginfo_to_user32(uinfo, &info)) return -EFAULT; } return ret;}asmlinkage longsys32_rt_sigqueueinfo (int pid, int sig, siginfo_t32 *uinfo){ extern asmlinkage long sys_rt_sigqueueinfo (int, int, siginfo_t *); extern int copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 *from); mm_segment_t old_fs = get_fs(); siginfo_t info; int ret; if (copy_siginfo_from_user32(&info, uinfo)) return -EFAULT; set_fs(KERNEL_DS); ret = sys_rt_sigqueueinfo(pid, sig, &info); set_fs(old_fs); return ret;}asmlinkage longsys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact){ struct k_sigaction new_ka, old_ka; unsigned int handler, restorer; int ret; if (act) { old_sigset32_t mask; ret = get_user(handler, &act->sa_handler); ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags); ret |= get_user(restorer, &act->sa_restorer); ret |= get_user(mask, &act->sa_mask); if (ret) return ret; sigact_set_handler(&new_ka, handler, restorer); siginitset(&new_ka.sa.sa_mask, mask); } ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { ret = put_user(IA32_SA_HANDLER(&old_ka), &oact->sa_handler); ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags); ret |= put_user(IA32_SA_RESTORER(&old_ka), &oact->sa_restorer); ret |= put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); } return ret;}static intsetup_sigcontext_ia32 (struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate, struct pt_regs *regs, unsigned long mask){ int err = 0; unsigned long flag;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -