diff options
Diffstat (limited to 'arch/mips/kernel/signal.c')
| -rw-r--r-- | arch/mips/kernel/signal.c | 138 |
1 files changed, 93 insertions, 45 deletions
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 9e224469c788..4a10f18a8806 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -25,7 +25,7 @@ #include <linux/compiler.h> #include <linux/syscalls.h> #include <linux/uaccess.h> -#include <linux/tracehook.h> +#include <linux/resume_user_mode.h> #include <asm/abi.h> #include <asm/asm.h> @@ -35,10 +35,10 @@ #include <asm/sim.h> #include <asm/ucontext.h> #include <asm/cpu-features.h> -#include <asm/war.h> #include <asm/dsp.h> #include <asm/inst.h> #include <asm/msa.h> +#include <asm/syscalls.h> #include "signal-common.h" @@ -52,7 +52,7 @@ struct sigframe { /* Matches struct ucontext from its uc_mcontext field onwards */ struct sigcontext sf_sc; sigset_t sf_mask; - unsigned long long sf_extcontext[0]; + unsigned long long sf_extcontext[]; }; struct rt_sigframe { @@ -62,6 +62,8 @@ struct rt_sigframe { struct ucontext rs_uc; }; +#ifdef CONFIG_MIPS_FP_SUPPORT + /* * Thread saved context copy to/from a signal context presumed to be on the * user stack, and therefore accessed with appropriate macros from uaccess.h. @@ -104,6 +106,20 @@ static int copy_fp_from_sigcontext(void __user *sc) return err; } +#else /* !CONFIG_MIPS_FP_SUPPORT */ + +static int copy_fp_to_sigcontext(void __user *sc) +{ + return 0; +} + +static int copy_fp_from_sigcontext(void __user *sc) +{ + return 0; +} + +#endif /* !CONFIG_MIPS_FP_SUPPORT */ + /* * Wrappers for the assembly _{save,restore}_fp_context functions. */ @@ -142,6 +158,8 @@ static inline void __user *sc_to_extcontext(void __user *sc) return &uc->uc_extcontext; } +#ifdef CONFIG_CPU_HAS_MSA + static int save_msa_extcontext(void __user *buf) { struct msa_extcontext __user *msa = buf; @@ -195,9 +213,6 @@ static int restore_msa_extcontext(void __user *buf, unsigned int size) unsigned int csr; int i, err; - if (!IS_ENABLED(CONFIG_CPU_HAS_MSA)) - return SIGSYS; - if (size != sizeof(*msa)) return -EINVAL; @@ -234,6 +249,20 @@ static int restore_msa_extcontext(void __user *buf, unsigned int size) return err; } +#else /* !CONFIG_CPU_HAS_MSA */ + +static int save_msa_extcontext(void __user *buf) +{ + return 0; +} + +static int restore_msa_extcontext(void __user *buf, unsigned int size) +{ + return SIGSYS; +} + +#endif /* !CONFIG_CPU_HAS_MSA */ + static int save_extcontext(void __user *buf) { int sz; @@ -516,6 +545,12 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) return err ?: protected_restore_fp_context(sc); } +#ifdef CONFIG_WAR_ICACHE_REFILLS +#define SIGMASK ~(cpu_icache_line_size()-1) +#else +#define SIGMASK ALMASK +#endif + void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size) { @@ -528,7 +563,14 @@ void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, sp = regs->regs[29]; /* - * FPU emulator may have it's own trampoline active just + * If we are on the alternate signal stack and would overflow it, don't. + * Return an always-bogus address instead so we will die with SIGSEGV. + */ + if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) + return (void __user __force *)(-1UL); + + /* + * FPU emulator may have its own trampoline active just * above the user stack, 16-bytes before the next lowest * 16 byte boundary. Try to avoid trashing it. */ @@ -536,7 +578,7 @@ void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, sp = sigsp(sp, ksig); - return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK)); + return (void __user *)((sp - frame_size) & SIGMASK); } /* @@ -561,7 +603,7 @@ SYSCALL_DEFINE3(sigaction, int, sig, const struct sigaction __user *, act, if (act) { old_sigset_t mask; - if (!access_ok(VERIFY_READ, act, sizeof(*act))) + if (!access_ok(act, sizeof(*act))) return -EFAULT; err |= __get_user(new_ka.sa.sa_handler, &act->sa_handler); err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); @@ -575,7 +617,7 @@ SYSCALL_DEFINE3(sigaction, int, sig, const struct sigaction __user *, act, ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { - if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) + if (!access_ok(oact, sizeof(*oact))) return -EFAULT; err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler); @@ -592,25 +634,27 @@ SYSCALL_DEFINE3(sigaction, int, sig, const struct sigaction __user *, act, #endif #ifdef CONFIG_TRAD_SIGNALS -asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs) +asmlinkage void sys_sigreturn(void) { struct sigframe __user *frame; + struct pt_regs *regs; sigset_t blocked; int sig; - frame = (struct sigframe __user *) regs.regs[29]; - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + regs = current_pt_regs(); + frame = (struct sigframe __user *)regs->regs[29]; + if (!access_ok(frame, sizeof(*frame))) goto badframe; if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked))) goto badframe; set_current_blocked(&blocked); - sig = restore_sigcontext(®s, &frame->sf_sc); + sig = restore_sigcontext(regs, &frame->sf_sc); if (sig < 0) goto badframe; else if (sig) - force_sig(sig, current); + force_sig(sig); /* * Don't let your children do this ... @@ -618,34 +662,36 @@ asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs) __asm__ __volatile__( "move\t$29, %0\n\t" "j\tsyscall_exit" - :/* no outputs */ - :"r" (®s)); + : /* no outputs */ + : "r" (regs)); /* Unreached */ badframe: - force_sig(SIGSEGV, current); + force_sig(SIGSEGV); } #endif /* CONFIG_TRAD_SIGNALS */ -asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) +asmlinkage void sys_rt_sigreturn(void) { struct rt_sigframe __user *frame; + struct pt_regs *regs; sigset_t set; int sig; - frame = (struct rt_sigframe __user *) regs.regs[29]; - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + regs = current_pt_regs(); + frame = (struct rt_sigframe __user *)regs->regs[29]; + if (!access_ok(frame, sizeof(*frame))) goto badframe; if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) goto badframe; set_current_blocked(&set); - sig = restore_sigcontext(®s, &frame->rs_uc.uc_mcontext); + sig = restore_sigcontext(regs, &frame->rs_uc.uc_mcontext); if (sig < 0) goto badframe; else if (sig) - force_sig(sig, current); + force_sig(sig); if (restore_altstack(&frame->rs_uc.uc_stack)) goto badframe; @@ -656,12 +702,12 @@ asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) __asm__ __volatile__( "move\t$29, %0\n\t" "j\tsyscall_exit" - :/* no outputs */ - :"r" (®s)); + : /* no outputs */ + : "r" (regs)); /* Unreached */ badframe: - force_sig(SIGSEGV, current); + force_sig(SIGSEGV); } #ifdef CONFIG_TRAD_SIGNALS @@ -672,7 +718,7 @@ static int setup_frame(void *sig_return, struct ksignal *ksig, int err = 0; frame = get_sigframe(ksig, regs, sizeof(*frame)); - if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + if (!access_ok(frame, sizeof (*frame))) return -EFAULT; err |= setup_sigcontext(regs, &frame->sf_sc); @@ -708,23 +754,25 @@ static int setup_rt_frame(void *sig_return, struct ksignal *ksig, struct pt_regs *regs, sigset_t *set) { struct rt_sigframe __user *frame; - int err = 0; frame = get_sigframe(ksig, regs, sizeof(*frame)); - if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + if (!access_ok(frame, sizeof (*frame))) return -EFAULT; /* Create siginfo. */ - err |= copy_siginfo_to_user(&frame->rs_info, &ksig->info); + if (copy_siginfo_to_user(&frame->rs_info, &ksig->info)) + return -EFAULT; /* Create the ucontext. */ - err |= __put_user(0, &frame->rs_uc.uc_flags); - err |= __put_user(NULL, &frame->rs_uc.uc_link); - err |= __save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]); - err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext); - err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); - - if (err) + if (__put_user(0, &frame->rs_uc.uc_flags)) + return -EFAULT; + if (__put_user(NULL, &frame->rs_uc.uc_link)) + return -EFAULT; + if (__save_altstack(&frame->rs_uc.uc_stack, regs->regs[29])) + return -EFAULT; + if (setup_sigcontext(regs, &frame->rs_uc.uc_mcontext)) + return -EFAULT; + if (__copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set))) return -EFAULT; /* @@ -791,7 +839,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) regs->regs[2] = EINTR; break; } - /* fallthrough */ + fallthrough; case ERESTARTNOINTR: regs->regs[7] = regs->regs[26]; regs->regs[2] = regs->regs[0]; @@ -801,6 +849,8 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) regs->regs[0] = 0; /* Don't deal with this again. */ } + rseq_signal_deliver(ksig, regs); + if (sig_uses_siginfo(&ksig->ka, abi)) ret = abi->setup_rt_frame(vdso + abi->vdso->off_rt_sigreturn, ksig, regs, oldset); @@ -862,18 +912,16 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, uprobe_notify_resume(regs); /* deal with pending signal delivery */ - if (thread_info_flags & _TIF_SIGPENDING) + if (thread_info_flags & (_TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL)) do_signal(regs); - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); - } + if (thread_info_flags & _TIF_NOTIFY_RESUME) + resume_user_mode_work(regs); user_enter(); } -#ifdef CONFIG_SMP +#if defined(CONFIG_SMP) && defined(CONFIG_MIPS_FP_SUPPORT) static int smp_save_fp_context(void __user *sc) { return raw_cpu_has_fpu @@ -901,7 +949,7 @@ static int signal_setup(void) (offsetof(struct rt_sigframe, rs_uc.uc_extcontext) - offsetof(struct rt_sigframe, rs_uc.uc_mcontext))); -#ifdef CONFIG_SMP +#if defined(CONFIG_SMP) && defined(CONFIG_MIPS_FP_SUPPORT) /* For now just do the cpu_has_fpu check when the functions are invoked */ save_fp_context = smp_save_fp_context; restore_fp_context = smp_restore_fp_context; |
