xref: /xnu-10002.81.5/bsd/uxkern/ux_exception.c (revision 5e3eaea39dcf651e66cb99ba7d70e32cc4a99587)
1 /*
2  * Copyright (c) 2000-2017 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /*
29  * Mach Operating System
30  * Copyright (c) 1987 Carnegie-Mellon University
31  * All rights reserved.  The CMU software License Agreement specifies
32  * the terms and conditions for use and redistribution.
33  */
34 
35 #include <sys/param.h>
36 
37 #include <mach/boolean.h>
38 #include <mach/exception.h>
39 #include <mach/kern_return.h>
40 
41 #include <sys/proc.h>
42 #include <sys/user.h>
43 #include <sys/systm.h>
44 #include <sys/vmparam.h>        /* MAXSSIZ */
45 
46 #include <sys/ux_exception.h>
47 
48 /*
49  * Translate Mach exceptions to UNIX signals.
50  *
51  * ux_exception translates a mach exception, code and subcode to
52  * a signal.  Calls machine_exception (machine dependent)
53  * to attempt translation first.
54  */
55 static int
ux_exception(int exception,mach_exception_code_t code,mach_exception_subcode_t subcode)56 ux_exception(int                        exception,
57     mach_exception_code_t      code,
58     mach_exception_subcode_t   subcode)
59 {
60 	int machine_signal = 0;
61 
62 	/* Try machine-dependent translation first. */
63 	if ((machine_signal = machine_exception(exception, code, subcode)) != 0) {
64 		return machine_signal;
65 	}
66 
67 	switch (exception) {
68 	case EXC_BAD_ACCESS:
69 		if (code == KERN_INVALID_ADDRESS) {
70 			return SIGSEGV;
71 		} else {
72 			return SIGBUS;
73 		}
74 
75 	case EXC_SYSCALL:
76 		if (send_sigsys) {
77 			return SIGSYS;
78 		}
79 		break;
80 
81 	case EXC_BAD_INSTRUCTION:
82 		return SIGILL;
83 
84 	case EXC_ARITHMETIC:
85 		return SIGFPE;
86 
87 	case EXC_EMULATION:
88 		return SIGEMT;
89 
90 	case EXC_SOFTWARE:
91 		switch (code) {
92 		case EXC_UNIX_BAD_SYSCALL:
93 			return SIGSYS;
94 		case EXC_UNIX_BAD_PIPE:
95 			return SIGPIPE;
96 		case EXC_UNIX_ABORT:
97 			return SIGABRT;
98 		case EXC_SOFT_SIGNAL:
99 			return SIGKILL;
100 		}
101 		break;
102 
103 	case EXC_BREAKPOINT:
104 		return SIGTRAP;
105 	}
106 
107 	return 0;
108 }
109 
110 /*
111  * Sends the corresponding UNIX signal to a thread that has triggered a Mach exception.
112  */
113 kern_return_t
handle_ux_exception(thread_t thread,int exception,mach_exception_code_t code,mach_exception_subcode_t subcode)114 handle_ux_exception(thread_t                    thread,
115     int                         exception,
116     mach_exception_code_t       code,
117     mach_exception_subcode_t    subcode)
118 {
119 	/* Returns +1 proc reference */
120 	proc_t p = proc_findthread(thread);
121 
122 	/* Can't deliver a signal without a bsd process reference */
123 	if (p == NULL) {
124 		return KERN_FAILURE;
125 	}
126 
127 	/* Translate exception and code to signal type */
128 	int ux_signal = ux_exception(exception, code, subcode);
129 
130 	uthread_t ut = get_bsdthread_info(thread);
131 
132 	/*
133 	 * Stack overflow should result in a SIGSEGV signal
134 	 * on the alternate stack.
135 	 * but we have one or more guard pages after the
136 	 * stack top, so we would get a KERN_PROTECTION_FAILURE
137 	 * exception instead of KERN_INVALID_ADDRESS, resulting in
138 	 * a SIGBUS signal.
139 	 * Detect that situation and select the correct signal.
140 	 */
141 	if (code == KERN_PROTECTION_FAILURE &&
142 	    ux_signal == SIGBUS) {
143 		user_addr_t sp = subcode;
144 
145 		user_addr_t stack_max = p->user_stack;
146 		user_addr_t stack_min = p->user_stack - MAXSSIZ;
147 		if (sp >= stack_min && sp < stack_max) {
148 			/*
149 			 * This is indeed a stack overflow.  Deliver a
150 			 * SIGSEGV signal.
151 			 */
152 			ux_signal = SIGSEGV;
153 
154 			/*
155 			 * If the thread/process is not ready to handle
156 			 * SIGSEGV on an alternate stack, force-deliver
157 			 * SIGSEGV with a SIG_DFL handler.
158 			 */
159 			int mask = sigmask(ux_signal);
160 			struct sigacts *ps = &p->p_sigacts;
161 			if ((p->p_sigignore & mask) ||
162 			    (ut->uu_sigwait & mask) ||
163 			    (ut->uu_sigmask & mask) ||
164 			    (SIGACTION(p, SIGSEGV) == SIG_IGN) ||
165 			    (!(ps->ps_sigonstack & mask))) {
166 				p->p_sigignore &= ~mask;
167 				p->p_sigcatch &= ~mask;
168 				proc_set_sigact(p, SIGSEGV, SIG_DFL);
169 				ut->uu_sigwait &= ~mask;
170 				ut->uu_sigmask &= ~mask;
171 			}
172 		}
173 	}
174 
175 	/* Send signal to thread */
176 	if (ux_signal != 0) {
177 		ut->uu_exception = exception;
178 		//ut->uu_code = code; // filled in by threadsignal
179 		ut->uu_subcode = subcode;
180 		threadsignal(thread, ux_signal, code, TRUE);
181 	}
182 
183 	proc_rele(p);
184 
185 	return KERN_SUCCESS;
186 }
187