xref: /openbmc/linux/arch/um/kernel/signal.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
10d1fb0a4SAlex Dewar // SPDX-License-Identifier: GPL-2.0
21d3468a6SJeff Dike /*
3ba180fd4SJeff Dike  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
41d3468a6SJeff Dike  */
51d3468a6SJeff Dike 
6c5d4bb17SJeff Dike #include <linux/module.h>
7c5d4bb17SJeff Dike #include <linux/ptrace.h>
8c5d4bb17SJeff Dike #include <linux/sched.h>
90dafcbe1SJohannes Berg #include <linux/ftrace.h>
10c5d4bb17SJeff Dike #include <asm/siginfo.h>
11c5d4bb17SJeff Dike #include <asm/signal.h>
12c5d4bb17SJeff Dike #include <asm/unistd.h>
1337185b33SAl Viro #include <frame_kern.h>
1437185b33SAl Viro #include <kern_util.h>
150dafcbe1SJohannes Berg #include <os.h>
161d3468a6SJeff Dike 
171d3468a6SJeff Dike EXPORT_SYMBOL(block_signals);
181d3468a6SJeff Dike EXPORT_SYMBOL(unblock_signals);
191d3468a6SJeff Dike 
block_signals_trace(void)200dafcbe1SJohannes Berg void block_signals_trace(void)
210dafcbe1SJohannes Berg {
220dafcbe1SJohannes Berg 	block_signals();
230dafcbe1SJohannes Berg 	if (current_thread_info())
240dafcbe1SJohannes Berg 		trace_hardirqs_off();
250dafcbe1SJohannes Berg }
260dafcbe1SJohannes Berg 
unblock_signals_trace(void)270dafcbe1SJohannes Berg void unblock_signals_trace(void)
280dafcbe1SJohannes Berg {
290dafcbe1SJohannes Berg 	if (current_thread_info())
300dafcbe1SJohannes Berg 		trace_hardirqs_on();
310dafcbe1SJohannes Berg 	unblock_signals();
320dafcbe1SJohannes Berg }
330dafcbe1SJohannes Berg 
um_trace_signals_on(void)340dafcbe1SJohannes Berg void um_trace_signals_on(void)
350dafcbe1SJohannes Berg {
360dafcbe1SJohannes Berg 	if (current_thread_info())
370dafcbe1SJohannes Berg 		trace_hardirqs_on();
380dafcbe1SJohannes Berg }
390dafcbe1SJohannes Berg 
um_trace_signals_off(void)400dafcbe1SJohannes Berg void um_trace_signals_off(void)
410dafcbe1SJohannes Berg {
420dafcbe1SJohannes Berg 	if (current_thread_info())
430dafcbe1SJohannes Berg 		trace_hardirqs_off();
440dafcbe1SJohannes Berg }
450dafcbe1SJohannes Berg 
461d3468a6SJeff Dike /*
471d3468a6SJeff Dike  * OK, we're invoking a handler
481d3468a6SJeff Dike  */
handle_signal(struct ksignal * ksig,struct pt_regs * regs)49307627eeSRichard Weinberger static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
501d3468a6SJeff Dike {
51b7f9a11aSAl Viro 	sigset_t *oldset = sigmask_to_save();
52f9a38eacSAl Viro 	int singlestep = 0;
531d3468a6SJeff Dike 	unsigned long sp;
541d3468a6SJeff Dike 	int err;
551d3468a6SJeff Dike 
56*c200e4bbSEric W. Biederman 	if (test_thread_flag(TIF_SINGLESTEP) && (current->ptrace & PT_PTRACED))
57f9a38eacSAl Viro 		singlestep = 1;
58f9a38eacSAl Viro 
591d3468a6SJeff Dike 	/* Did we come from a system call? */
601d3468a6SJeff Dike 	if (PT_REGS_SYSCALL_NR(regs) >= 0) {
611d3468a6SJeff Dike 		/* If so, check system call restarting.. */
621d3468a6SJeff Dike 		switch (PT_REGS_SYSCALL_RET(regs)) {
631d3468a6SJeff Dike 		case -ERESTART_RESTARTBLOCK:
641d3468a6SJeff Dike 		case -ERESTARTNOHAND:
651d3468a6SJeff Dike 			PT_REGS_SYSCALL_RET(regs) = -EINTR;
661d3468a6SJeff Dike 			break;
671d3468a6SJeff Dike 
681d3468a6SJeff Dike 		case -ERESTARTSYS:
69307627eeSRichard Weinberger 			if (!(ksig->ka.sa.sa_flags & SA_RESTART)) {
701d3468a6SJeff Dike 				PT_REGS_SYSCALL_RET(regs) = -EINTR;
711d3468a6SJeff Dike 				break;
721d3468a6SJeff Dike 			}
73df561f66SGustavo A. R. Silva 			fallthrough;
741d3468a6SJeff Dike 		case -ERESTARTNOINTR:
751d3468a6SJeff Dike 			PT_REGS_RESTART_SYSCALL(regs);
761d3468a6SJeff Dike 			PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
771d3468a6SJeff Dike 			break;
781d3468a6SJeff Dike 		}
791d3468a6SJeff Dike 	}
801d3468a6SJeff Dike 
811d3468a6SJeff Dike 	sp = PT_REGS_SP(regs);
82307627eeSRichard Weinberger 	if ((ksig->ka.sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0))
831d3468a6SJeff Dike 		sp = current->sas_ss_sp + current->sas_ss_size;
841d3468a6SJeff Dike 
851d3468a6SJeff Dike #ifdef CONFIG_ARCH_HAS_SC_SIGNALS
86307627eeSRichard Weinberger 	if (!(ksig->ka.sa.sa_flags & SA_SIGINFO))
87307627eeSRichard Weinberger 		err = setup_signal_stack_sc(sp, ksig, regs, oldset);
881d3468a6SJeff Dike 	else
891d3468a6SJeff Dike #endif
90307627eeSRichard Weinberger 		err = setup_signal_stack_si(sp, ksig, regs, oldset);
911d3468a6SJeff Dike 
92307627eeSRichard Weinberger 	signal_setup_done(err, ksig, singlestep);
931d3468a6SJeff Dike }
941d3468a6SJeff Dike 
do_signal(struct pt_regs * regs)95ccaee5f8SIngo Molnar void do_signal(struct pt_regs *regs)
961d3468a6SJeff Dike {
97307627eeSRichard Weinberger 	struct ksignal ksig;
98307627eeSRichard Weinberger 	int handled_sig = 0;
991d3468a6SJeff Dike 
100322740efSRichard Weinberger 	while (get_signal(&ksig)) {
1011d3468a6SJeff Dike 		handled_sig = 1;
1021d3468a6SJeff Dike 		/* Whee!  Actually deliver the signal.  */
103307627eeSRichard Weinberger 		handle_signal(&ksig, regs);
1041d3468a6SJeff Dike 	}
1051d3468a6SJeff Dike 
1061d3468a6SJeff Dike 	/* Did we come from a system call? */
1071d3468a6SJeff Dike 	if (!handled_sig && (PT_REGS_SYSCALL_NR(regs) >= 0)) {
1081d3468a6SJeff Dike 		/* Restart the system call - no handlers present */
1091d3468a6SJeff Dike 		switch (PT_REGS_SYSCALL_RET(regs)) {
1101d3468a6SJeff Dike 		case -ERESTARTNOHAND:
1111d3468a6SJeff Dike 		case -ERESTARTSYS:
1121d3468a6SJeff Dike 		case -ERESTARTNOINTR:
1131d3468a6SJeff Dike 			PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
1141d3468a6SJeff Dike 			PT_REGS_RESTART_SYSCALL(regs);
1151d3468a6SJeff Dike 			break;
1161d3468a6SJeff Dike 		case -ERESTART_RESTARTBLOCK:
1171d3468a6SJeff Dike 			PT_REGS_ORIG_SYSCALL(regs) = __NR_restart_syscall;
1181d3468a6SJeff Dike 			PT_REGS_RESTART_SYSCALL(regs);
1191d3468a6SJeff Dike 			break;
1201d3468a6SJeff Dike 		}
1211d3468a6SJeff Dike 	}
1221d3468a6SJeff Dike 
123ba180fd4SJeff Dike 	/*
124ba180fd4SJeff Dike 	 * This closes a way to execute a system call on the host.  If
1251d3468a6SJeff Dike 	 * you set a breakpoint on a system call instruction and singlestep
1261d3468a6SJeff Dike 	 * from it, the tracing thread used to PTRACE_SINGLESTEP the process
1271d3468a6SJeff Dike 	 * rather than PTRACE_SYSCALL it, allowing the system call to execute
1281d3468a6SJeff Dike 	 * on the host.  The tracing thread will check this flag and
1291d3468a6SJeff Dike 	 * PTRACE_SYSCALL if necessary.
1301d3468a6SJeff Dike 	 */
131*c200e4bbSEric W. Biederman 	if (test_thread_flag(TIF_SINGLESTEP))
1321d3468a6SJeff Dike 		current->thread.singlestep_syscall =
1331d3468a6SJeff Dike 			is_syscall(PT_REGS_IP(&current->thread.regs));
1341d3468a6SJeff Dike 
135ba180fd4SJeff Dike 	/*
136ba180fd4SJeff Dike 	 * if there's no signal to deliver, we just put the saved sigmask
137ba180fd4SJeff Dike 	 * back
138ba180fd4SJeff Dike 	 */
13951a7b448SAl Viro 	if (!handled_sig)
14051a7b448SAl Viro 		restore_saved_sigmask();
1411d3468a6SJeff Dike }
142