xref: /xnu-8019.80.24/bsd/uxkern/ux_exception.c (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
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_BAD_INSTRUCTION:
76 		return SIGILL;
77 
78 	case EXC_ARITHMETIC:
79 		return SIGFPE;
80 
81 	case EXC_EMULATION:
82 		return SIGEMT;
83 
84 	case EXC_SOFTWARE:
85 		switch (code) {
86 		case EXC_UNIX_BAD_SYSCALL:
87 			return SIGSYS;
88 		case EXC_UNIX_BAD_PIPE:
89 			return SIGPIPE;
90 		case EXC_UNIX_ABORT:
91 			return SIGABRT;
92 		case EXC_SOFT_SIGNAL:
93 			return SIGKILL;
94 		}
95 		break;
96 
97 	case EXC_BREAKPOINT:
98 		return SIGTRAP;
99 	}
100 
101 	return 0;
102 }
103 
104 /*
105  * Sends the corresponding UNIX signal to a thread that has triggered a Mach exception.
106  */
107 kern_return_t
handle_ux_exception(thread_t thread,int exception,mach_exception_code_t code,mach_exception_subcode_t subcode)108 handle_ux_exception(thread_t                    thread,
109     int                         exception,
110     mach_exception_code_t       code,
111     mach_exception_subcode_t    subcode)
112 {
113 	/* Returns +1 proc reference */
114 	proc_t p = proc_findthread(thread);
115 
116 	/* Can't deliver a signal without a bsd process reference */
117 	if (p == NULL) {
118 		return KERN_FAILURE;
119 	}
120 
121 	/* Translate exception and code to signal type */
122 	int ux_signal = ux_exception(exception, code, subcode);
123 
124 	uthread_t ut = get_bsdthread_info(thread);
125 
126 	/*
127 	 * Stack overflow should result in a SIGSEGV signal
128 	 * on the alternate stack.
129 	 * but we have one or more guard pages after the
130 	 * stack top, so we would get a KERN_PROTECTION_FAILURE
131 	 * exception instead of KERN_INVALID_ADDRESS, resulting in
132 	 * a SIGBUS signal.
133 	 * Detect that situation and select the correct signal.
134 	 */
135 	if (code == KERN_PROTECTION_FAILURE &&
136 	    ux_signal == SIGBUS) {
137 		user_addr_t sp = subcode;
138 
139 		user_addr_t stack_max = p->user_stack;
140 		user_addr_t stack_min = p->user_stack - MAXSSIZ;
141 		if (sp >= stack_min && sp < stack_max) {
142 			/*
143 			 * This is indeed a stack overflow.  Deliver a
144 			 * SIGSEGV signal.
145 			 */
146 			ux_signal = SIGSEGV;
147 
148 			/*
149 			 * If the thread/process is not ready to handle
150 			 * SIGSEGV on an alternate stack, force-deliver
151 			 * SIGSEGV with a SIG_DFL handler.
152 			 */
153 			int mask = sigmask(ux_signal);
154 			struct sigacts *ps = &p->p_sigacts;
155 			if ((p->p_sigignore & mask) ||
156 			    (ut->uu_sigwait & mask) ||
157 			    (ut->uu_sigmask & mask) ||
158 			    (SIGACTION(p, SIGSEGV) == SIG_IGN) ||
159 			    (!(ps->ps_sigonstack & mask))) {
160 				p->p_sigignore &= ~mask;
161 				p->p_sigcatch &= ~mask;
162 				proc_set_sigact(p, SIGSEGV, SIG_DFL);
163 				ut->uu_sigwait &= ~mask;
164 				ut->uu_sigmask &= ~mask;
165 			}
166 		}
167 	}
168 
169 	/* Send signal to thread */
170 	if (ux_signal != 0) {
171 		ut->uu_exception = exception;
172 		//ut->uu_code = code; // filled in by threadsignal
173 		ut->uu_subcode = subcode;
174 		threadsignal(thread, ux_signal, code, TRUE);
175 	}
176 
177 	proc_rele(p);
178 
179 	return KERN_SUCCESS;
180 }
181