xref: /linux/arch/riscv/kernel/compat_signal.c (revision 7383ee05)
17383ee05SGuo Ren // SPDX-License-Identifier: GPL-2.0-or-later
27383ee05SGuo Ren 
37383ee05SGuo Ren #include <linux/compat.h>
47383ee05SGuo Ren #include <linux/signal.h>
57383ee05SGuo Ren #include <linux/uaccess.h>
67383ee05SGuo Ren #include <linux/syscalls.h>
77383ee05SGuo Ren #include <linux/linkage.h>
87383ee05SGuo Ren 
97383ee05SGuo Ren #include <asm/csr.h>
107383ee05SGuo Ren #include <asm/signal32.h>
117383ee05SGuo Ren #include <asm/switch_to.h>
127383ee05SGuo Ren #include <asm/ucontext.h>
137383ee05SGuo Ren #include <asm/vdso.h>
147383ee05SGuo Ren 
157383ee05SGuo Ren #define COMPAT_DEBUG_SIG 0
167383ee05SGuo Ren 
177383ee05SGuo Ren struct compat_sigcontext {
187383ee05SGuo Ren 	struct compat_user_regs_struct sc_regs;
197383ee05SGuo Ren 	union __riscv_fp_state sc_fpregs;
207383ee05SGuo Ren };
217383ee05SGuo Ren 
227383ee05SGuo Ren struct compat_ucontext {
237383ee05SGuo Ren 	compat_ulong_t		uc_flags;
247383ee05SGuo Ren 	struct compat_ucontext	*uc_link;
257383ee05SGuo Ren 	compat_stack_t		uc_stack;
267383ee05SGuo Ren 	sigset_t		uc_sigmask;
277383ee05SGuo Ren 	/* There's some padding here to allow sigset_t to be expanded in the
287383ee05SGuo Ren 	 * future.  Though this is unlikely, other architectures put uc_sigmask
297383ee05SGuo Ren 	 * at the end of this structure and explicitly state it can be
307383ee05SGuo Ren 	 * expanded, so we didn't want to box ourselves in here. */
317383ee05SGuo Ren 	__u8		  __unused[1024 / 8 - sizeof(sigset_t)];
327383ee05SGuo Ren 	/* We can't put uc_sigmask at the end of this structure because we need
337383ee05SGuo Ren 	 * to be able to expand sigcontext in the future.  For example, the
347383ee05SGuo Ren 	 * vector ISA extension will almost certainly add ISA state.  We want
357383ee05SGuo Ren 	 * to ensure all user-visible ISA state can be saved and restored via a
367383ee05SGuo Ren 	 * ucontext, so we're putting this at the end in order to allow for
377383ee05SGuo Ren 	 * infinite extensibility.  Since we know this will be extended and we
387383ee05SGuo Ren 	 * assume sigset_t won't be extended an extreme amount, we're
397383ee05SGuo Ren 	 * prioritizing this. */
407383ee05SGuo Ren 	struct compat_sigcontext uc_mcontext;
417383ee05SGuo Ren };
427383ee05SGuo Ren 
437383ee05SGuo Ren struct compat_rt_sigframe {
447383ee05SGuo Ren 	struct compat_siginfo info;
457383ee05SGuo Ren 	struct compat_ucontext uc;
467383ee05SGuo Ren };
477383ee05SGuo Ren 
487383ee05SGuo Ren #ifdef CONFIG_FPU
compat_restore_fp_state(struct pt_regs * regs,union __riscv_fp_state __user * sc_fpregs)497383ee05SGuo Ren static long compat_restore_fp_state(struct pt_regs *regs,
507383ee05SGuo Ren 	union __riscv_fp_state __user *sc_fpregs)
517383ee05SGuo Ren {
527383ee05SGuo Ren 	long err;
537383ee05SGuo Ren 	struct __riscv_d_ext_state __user *state = &sc_fpregs->d;
547383ee05SGuo Ren 	size_t i;
557383ee05SGuo Ren 
567383ee05SGuo Ren 	err = __copy_from_user(&current->thread.fstate, state, sizeof(*state));
577383ee05SGuo Ren 	if (unlikely(err))
587383ee05SGuo Ren 		return err;
597383ee05SGuo Ren 
607383ee05SGuo Ren 	fstate_restore(current, regs);
617383ee05SGuo Ren 
627383ee05SGuo Ren 	/* We support no other extension state at this time. */
637383ee05SGuo Ren 	for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) {
647383ee05SGuo Ren 		u32 value;
657383ee05SGuo Ren 
667383ee05SGuo Ren 		err = __get_user(value, &sc_fpregs->q.reserved[i]);
677383ee05SGuo Ren 		if (unlikely(err))
687383ee05SGuo Ren 			break;
697383ee05SGuo Ren 		if (value != 0)
707383ee05SGuo Ren 			return -EINVAL;
717383ee05SGuo Ren 	}
727383ee05SGuo Ren 
737383ee05SGuo Ren 	return err;
747383ee05SGuo Ren }
757383ee05SGuo Ren 
compat_save_fp_state(struct pt_regs * regs,union __riscv_fp_state __user * sc_fpregs)767383ee05SGuo Ren static long compat_save_fp_state(struct pt_regs *regs,
777383ee05SGuo Ren 			  union __riscv_fp_state __user *sc_fpregs)
787383ee05SGuo Ren {
797383ee05SGuo Ren 	long err;
807383ee05SGuo Ren 	struct __riscv_d_ext_state __user *state = &sc_fpregs->d;
817383ee05SGuo Ren 	size_t i;
827383ee05SGuo Ren 
837383ee05SGuo Ren 	fstate_save(current, regs);
847383ee05SGuo Ren 	err = __copy_to_user(state, &current->thread.fstate, sizeof(*state));
857383ee05SGuo Ren 	if (unlikely(err))
867383ee05SGuo Ren 		return err;
877383ee05SGuo Ren 
887383ee05SGuo Ren 	/* We support no other extension state at this time. */
897383ee05SGuo Ren 	for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) {
907383ee05SGuo Ren 		err = __put_user(0, &sc_fpregs->q.reserved[i]);
917383ee05SGuo Ren 		if (unlikely(err))
927383ee05SGuo Ren 			break;
937383ee05SGuo Ren 	}
947383ee05SGuo Ren 
957383ee05SGuo Ren 	return err;
967383ee05SGuo Ren }
977383ee05SGuo Ren #else
987383ee05SGuo Ren #define compat_save_fp_state(task, regs) (0)
997383ee05SGuo Ren #define compat_restore_fp_state(task, regs) (0)
1007383ee05SGuo Ren #endif
1017383ee05SGuo Ren 
compat_restore_sigcontext(struct pt_regs * regs,struct compat_sigcontext __user * sc)1027383ee05SGuo Ren static long compat_restore_sigcontext(struct pt_regs *regs,
1037383ee05SGuo Ren 	struct compat_sigcontext __user *sc)
1047383ee05SGuo Ren {
1057383ee05SGuo Ren 	long err;
1067383ee05SGuo Ren 	struct compat_user_regs_struct cregs;
1077383ee05SGuo Ren 
1087383ee05SGuo Ren 	/* sc_regs is structured the same as the start of pt_regs */
1097383ee05SGuo Ren 	err = __copy_from_user(&cregs, &sc->sc_regs, sizeof(sc->sc_regs));
1107383ee05SGuo Ren 
1117383ee05SGuo Ren 	cregs_to_regs(&cregs, regs);
1127383ee05SGuo Ren 
1137383ee05SGuo Ren 	/* Restore the floating-point state. */
1147383ee05SGuo Ren 	if (has_fpu())
1157383ee05SGuo Ren 		err |= compat_restore_fp_state(regs, &sc->sc_fpregs);
1167383ee05SGuo Ren 	return err;
1177383ee05SGuo Ren }
1187383ee05SGuo Ren 
COMPAT_SYSCALL_DEFINE0(rt_sigreturn)1197383ee05SGuo Ren COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
1207383ee05SGuo Ren {
1217383ee05SGuo Ren 	struct pt_regs *regs = current_pt_regs();
1227383ee05SGuo Ren 	struct compat_rt_sigframe __user *frame;
1237383ee05SGuo Ren 	struct task_struct *task;
1247383ee05SGuo Ren 	sigset_t set;
1257383ee05SGuo Ren 
1267383ee05SGuo Ren 	/* Always make any pending restarted system calls return -EINTR */
1277383ee05SGuo Ren 	current->restart_block.fn = do_no_restart_syscall;
1287383ee05SGuo Ren 
1297383ee05SGuo Ren 	frame = (struct compat_rt_sigframe __user *)regs->sp;
1307383ee05SGuo Ren 
1317383ee05SGuo Ren 	if (!access_ok(frame, sizeof(*frame)))
1327383ee05SGuo Ren 		goto badframe;
1337383ee05SGuo Ren 
1347383ee05SGuo Ren 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
1357383ee05SGuo Ren 		goto badframe;
1367383ee05SGuo Ren 
1377383ee05SGuo Ren 	set_current_blocked(&set);
1387383ee05SGuo Ren 
1397383ee05SGuo Ren 	if (compat_restore_sigcontext(regs, &frame->uc.uc_mcontext))
1407383ee05SGuo Ren 		goto badframe;
1417383ee05SGuo Ren 
1427383ee05SGuo Ren 	if (compat_restore_altstack(&frame->uc.uc_stack))
1437383ee05SGuo Ren 		goto badframe;
1447383ee05SGuo Ren 
1457383ee05SGuo Ren 	return regs->a0;
1467383ee05SGuo Ren 
1477383ee05SGuo Ren badframe:
1487383ee05SGuo Ren 	task = current;
1497383ee05SGuo Ren 	if (show_unhandled_signals) {
1507383ee05SGuo Ren 		pr_info_ratelimited(
1517383ee05SGuo Ren 			"%s[%d]: bad frame in %s: frame=%p pc=%p sp=%p\n",
1527383ee05SGuo Ren 			task->comm, task_pid_nr(task), __func__,
1537383ee05SGuo Ren 			frame, (void *)regs->epc, (void *)regs->sp);
1547383ee05SGuo Ren 	}
1557383ee05SGuo Ren 	force_sig(SIGSEGV);
1567383ee05SGuo Ren 	return 0;
1577383ee05SGuo Ren }
1587383ee05SGuo Ren 
compat_setup_sigcontext(struct compat_rt_sigframe __user * frame,struct pt_regs * regs)1597383ee05SGuo Ren static long compat_setup_sigcontext(struct compat_rt_sigframe __user *frame,
1607383ee05SGuo Ren 	struct pt_regs *regs)
1617383ee05SGuo Ren {
1627383ee05SGuo Ren 	struct compat_sigcontext __user *sc = &frame->uc.uc_mcontext;
1637383ee05SGuo Ren 	struct compat_user_regs_struct cregs;
1647383ee05SGuo Ren 	long err;
1657383ee05SGuo Ren 
1667383ee05SGuo Ren 	regs_to_cregs(&cregs, regs);
1677383ee05SGuo Ren 
1687383ee05SGuo Ren 	/* sc_regs is structured the same as the start of pt_regs */
1697383ee05SGuo Ren 	err = __copy_to_user(&sc->sc_regs, &cregs, sizeof(sc->sc_regs));
1707383ee05SGuo Ren 	/* Save the floating-point state. */
1717383ee05SGuo Ren 	if (has_fpu())
1727383ee05SGuo Ren 		err |= compat_save_fp_state(regs, &sc->sc_fpregs);
1737383ee05SGuo Ren 	return err;
1747383ee05SGuo Ren }
1757383ee05SGuo Ren 
compat_get_sigframe(struct ksignal * ksig,struct pt_regs * regs,size_t framesize)1767383ee05SGuo Ren static inline void __user *compat_get_sigframe(struct ksignal *ksig,
1777383ee05SGuo Ren 	struct pt_regs *regs, size_t framesize)
1787383ee05SGuo Ren {
1797383ee05SGuo Ren 	unsigned long sp;
1807383ee05SGuo Ren 	/* Default to using normal stack */
1817383ee05SGuo Ren 	sp = regs->sp;
1827383ee05SGuo Ren 
1837383ee05SGuo Ren 	/*
1847383ee05SGuo Ren 	 * If we are on the alternate signal stack and would overflow it, don't.
1857383ee05SGuo Ren 	 * Return an always-bogus address instead so we will die with SIGSEGV.
1867383ee05SGuo Ren 	 */
1877383ee05SGuo Ren 	if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize)))
1887383ee05SGuo Ren 		return (void __user __force *)(-1UL);
1897383ee05SGuo Ren 
1907383ee05SGuo Ren 	/* This is the X/Open sanctioned signal stack switching. */
1917383ee05SGuo Ren 	sp = sigsp(sp, ksig) - framesize;
1927383ee05SGuo Ren 
1937383ee05SGuo Ren 	/* Align the stack frame. */
1947383ee05SGuo Ren 	sp &= ~0xfUL;
1957383ee05SGuo Ren 
1967383ee05SGuo Ren 	return (void __user *)sp;
1977383ee05SGuo Ren }
1987383ee05SGuo Ren 
compat_setup_rt_frame(struct ksignal * ksig,sigset_t * set,struct pt_regs * regs)1997383ee05SGuo Ren int compat_setup_rt_frame(struct ksignal *ksig, sigset_t *set,
2007383ee05SGuo Ren 	struct pt_regs *regs)
2017383ee05SGuo Ren {
2027383ee05SGuo Ren 	struct compat_rt_sigframe __user *frame;
2037383ee05SGuo Ren 	long err = 0;
2047383ee05SGuo Ren 
2057383ee05SGuo Ren 	frame = compat_get_sigframe(ksig, regs, sizeof(*frame));
2067383ee05SGuo Ren 	if (!access_ok(frame, sizeof(*frame)))
2077383ee05SGuo Ren 		return -EFAULT;
2087383ee05SGuo Ren 
2097383ee05SGuo Ren 	err |= copy_siginfo_to_user32(&frame->info, &ksig->info);
2107383ee05SGuo Ren 
2117383ee05SGuo Ren 	/* Create the ucontext. */
2127383ee05SGuo Ren 	err |= __put_user(0, &frame->uc.uc_flags);
2137383ee05SGuo Ren 	err |= __put_user(NULL, &frame->uc.uc_link);
2147383ee05SGuo Ren 	err |= __compat_save_altstack(&frame->uc.uc_stack, regs->sp);
2157383ee05SGuo Ren 	err |= compat_setup_sigcontext(frame, regs);
2167383ee05SGuo Ren 	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
2177383ee05SGuo Ren 	if (err)
2187383ee05SGuo Ren 		return -EFAULT;
2197383ee05SGuo Ren 
2207383ee05SGuo Ren 	regs->ra = (unsigned long)COMPAT_VDSO_SYMBOL(
2217383ee05SGuo Ren 			current->mm->context.vdso, rt_sigreturn);
2227383ee05SGuo Ren 
2237383ee05SGuo Ren 	/*
2247383ee05SGuo Ren 	 * Set up registers for signal handler.
2257383ee05SGuo Ren 	 * Registers that we don't modify keep the value they had from
2267383ee05SGuo Ren 	 * user-space at the time we took the signal.
2277383ee05SGuo Ren 	 * We always pass siginfo and mcontext, regardless of SA_SIGINFO,
2287383ee05SGuo Ren 	 * since some things rely on this (e.g. glibc's debug/segfault.c).
2297383ee05SGuo Ren 	 */
2307383ee05SGuo Ren 	regs->epc = (unsigned long)ksig->ka.sa.sa_handler;
2317383ee05SGuo Ren 	regs->sp = (unsigned long)frame;
2327383ee05SGuo Ren 	regs->a0 = ksig->sig;                     /* a0: signal number */
2337383ee05SGuo Ren 	regs->a1 = (unsigned long)(&frame->info); /* a1: siginfo pointer */
2347383ee05SGuo Ren 	regs->a2 = (unsigned long)(&frame->uc);   /* a2: ucontext pointer */
2357383ee05SGuo Ren 
2367383ee05SGuo Ren #if COMPAT_DEBUG_SIG
2377383ee05SGuo Ren 	pr_info("SIG deliver (%s:%d): sig=%d pc=%p ra=%p sp=%p\n",
2387383ee05SGuo Ren 		current->comm, task_pid_nr(current), ksig->sig,
2397383ee05SGuo Ren 		(void *)regs->epc, (void *)regs->ra, frame);
2407383ee05SGuo Ren #endif
2417383ee05SGuo Ren 
2427383ee05SGuo Ren 	return 0;
2437383ee05SGuo Ren }
244