]> git.saurik.com Git - apple/xnu.git/blame - bsd/uxkern/ux_exception.c
xnu-3789.31.2.tar.gz
[apple/xnu.git] / bsd / uxkern / ux_exception.c
CommitLineData
1c79356b 1/*
39037602 2 * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
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/*
36 *********************************************************************
37 * HISTORY
38 **********************************************************************
39 */
40
41#include <sys/param.h>
42
43#include <mach/boolean.h>
44#include <mach/exception.h>
45#include <mach/kern_return.h>
46#include <mach/message.h>
47#include <mach/port.h>
91447636 48#include <mach/mach_port.h>
1c79356b 49#include <mach/mig_errors.h>
91447636 50#include <mach/exc_server.h>
2d21ac55 51#include <mach/mach_exc_server.h>
1c79356b
A
52#include <kern/task.h>
53#include <kern/thread.h>
9bccf70c 54#include <kern/sched_prim.h>
1c79356b
A
55#include <kern/kalloc.h>
56
57#include <sys/proc.h>
58#include <sys/user.h>
59#include <sys/systm.h>
60#include <sys/ux_exception.h>
2d21ac55 61#include <sys/vmparam.h> /* MAXSSIZ */
1c79356b 62
91447636 63#include <vm/vm_protos.h> /* get_task_ipcspace() */
91447636
A
64/*
65 * XXX Things that should be retrieved from Mach headers, but aren't
66 */
67struct ipc_object;
68extern kern_return_t ipc_object_copyin(ipc_space_t space, mach_port_name_t name,
69 mach_msg_type_name_t msgt_name, struct ipc_object **objectp);
70extern mach_msg_return_t mach_msg_receive(mach_msg_header_t *msg,
71 mach_msg_option_t option, mach_msg_size_t rcv_size,
72 mach_port_name_t rcv_name, mach_msg_timeout_t rcv_timeout,
73 void (*continuation)(mach_msg_return_t),
74 mach_msg_size_t slist_size);
75extern mach_msg_return_t mach_msg_send(mach_msg_header_t *msg,
76 mach_msg_option_t option, mach_msg_size_t send_size,
77 mach_msg_timeout_t send_timeout, mach_port_name_t notify);
78extern thread_t convert_port_to_thread(ipc_port_t port);
3e170ce0 79extern void ipc_port_release_send(ipc_port_t port);
91447636
A
80
81
82
2d21ac55 83
1c79356b
A
84/*
85 * Unix exception handler.
86 */
87
2d21ac55
A
88static void ux_exception(int exception, mach_exception_code_t code,
89 mach_exception_subcode_t subcode,
90 int *ux_signal, mach_exception_code_t *ux_code);
1c79356b 91
fe8ab488 92#if defined(__x86_64__) || defined(__arm64__)
b0d623f7
A
93mach_port_t ux_exception_port;
94#else
1c79356b 95mach_port_name_t ux_exception_port;
b0d623f7
A
96#endif /* __x86_64__ */
97
1c79356b
A
98static task_t ux_handler_self;
99
39037602
A
100__attribute__((noreturn))
101static void
1c79356b
A
102ux_handler(void)
103{
104 task_t self = current_task();
105 mach_port_name_t exc_port_name;
106 mach_port_name_t exc_set_name;
107
1c79356b
A
108 /* self->kernel_vm_space = TRUE; */
109 ux_handler_self = self;
110
111
112 /*
113 * Allocate a port set that we will receive on.
114 */
115 if (mach_port_allocate(get_task_ipcspace(ux_handler_self), MACH_PORT_RIGHT_PORT_SET, &exc_set_name) != MACH_MSG_SUCCESS)
116 panic("ux_handler: port_set_allocate failed");
117
118 /*
119 * Allocate an exception port and use object_copyin to
120 * translate it to the global name. Put it into the set.
121 */
122 if (mach_port_allocate(get_task_ipcspace(ux_handler_self), MACH_PORT_RIGHT_RECEIVE, &exc_port_name) != MACH_MSG_SUCCESS)
123 panic("ux_handler: port_allocate failed");
124 if (mach_port_move_member(get_task_ipcspace(ux_handler_self),
125 exc_port_name, exc_set_name) != MACH_MSG_SUCCESS)
126 panic("ux_handler: port_set_add failed");
127
128 if (ipc_object_copyin(get_task_ipcspace(self), exc_port_name,
129 MACH_MSG_TYPE_MAKE_SEND,
130 (void *) &ux_exception_port) != MACH_MSG_SUCCESS)
131 panic("ux_handler: object_copyin(ux_exception_port) failed");
132
cf7d32b8 133 proc_list_lock();
1c79356b 134 thread_wakeup(&ux_exception_port);
cf7d32b8 135 proc_list_unlock();
1c79356b
A
136
137 /* Message handling loop. */
138
139 for (;;) {
140 struct rep_msg {
141 mach_msg_header_t Head;
142 NDR_record_t NDR;
143 kern_return_t RetCode;
144 } rep_msg;
145 struct exc_msg {
146 mach_msg_header_t Head;
147 /* start of the kernel processed data */
148 mach_msg_body_t msgh_body;
149 mach_msg_port_descriptor_t thread;
150 mach_msg_port_descriptor_t task;
151 /* end of the kernel processed data */
152 NDR_record_t NDR;
153 exception_type_t exception;
154 mach_msg_type_number_t codeCnt;
2d21ac55 155 mach_exception_data_t code;
1c79356b
A
156 /* some times RCV_TO_LARGE probs */
157 char pad[512];
158 } exc_msg;
159 mach_port_name_t reply_port;
160 kern_return_t result;
161
b0d623f7 162 exc_msg.Head.msgh_local_port = CAST_MACH_NAME_TO_PORT(exc_set_name);
1c79356b
A
163 exc_msg.Head.msgh_size = sizeof (exc_msg);
164#if 0
165 result = mach_msg_receive(&exc_msg.Head);
166#else
167 result = mach_msg_receive(&exc_msg.Head, MACH_RCV_MSG,
168 sizeof (exc_msg), exc_set_name,
169 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL,
170 0);
171#endif
172 if (result == MACH_MSG_SUCCESS) {
b0d623f7 173 reply_port = CAST_MACH_PORT_TO_NAME(exc_msg.Head.msgh_remote_port);
1c79356b 174
b0d623f7
A
175 if (mach_exc_server(&exc_msg.Head, &rep_msg.Head)) {
176 result = mach_msg_send(&rep_msg.Head, MACH_SEND_MSG,
1c79356b 177 sizeof (rep_msg),MACH_MSG_TIMEOUT_NONE,MACH_PORT_NULL);
b0d623f7
A
178 if (reply_port != 0 && result != MACH_MSG_SUCCESS)
179 mach_port_deallocate(get_task_ipcspace(ux_handler_self), reply_port);
180 }
1c79356b 181
1c79356b
A
182 }
183 else if (result == MACH_RCV_TOO_LARGE)
184 /* ignore oversized messages */;
185 else
186 panic("exception_handler");
187 }
1c79356b
A
188}
189
190void
191ux_handler_init(void)
192{
b0d623f7
A
193 thread_t thread = THREAD_NULL;
194
1c79356b 195 ux_exception_port = MACH_PORT_NULL;
b0d623f7
A
196 (void) kernel_thread_start((thread_continue_t)ux_handler, NULL, &thread);
197 thread_deallocate(thread);
cf7d32b8 198 proc_list_lock();
1c79356b 199 if (ux_exception_port == MACH_PORT_NULL) {
cf7d32b8 200 (void)msleep(&ux_exception_port, proc_list_mlock, 0, "ux_handler_wait", 0);
2d21ac55 201 }
cf7d32b8 202 proc_list_unlock();
1c79356b
A
203}
204
205kern_return_t
206catch_exception_raise(
91447636
A
207 __unused mach_port_t exception_port,
208 mach_port_t thread,
209 mach_port_t task,
210 exception_type_t exception,
211 exception_data_t code,
212 __unused mach_msg_type_number_t codeCnt
1c79356b
A
213)
214{
2d21ac55
A
215 mach_exception_data_type_t big_code[EXCEPTION_CODE_MAX];
216 big_code[0] = code[0];
217 big_code[1] = code[1];
218
219 return catch_mach_exception_raise(exception_port,
220 thread,
221 task,
222 exception,
223 big_code,
224 codeCnt);
225
226}
227
228kern_return_t
229catch_mach_exception_raise(
230 __unused mach_port_t exception_port,
231 mach_port_t thread,
232 mach_port_t task,
233 exception_type_t exception,
234 mach_exception_data_t code,
235 __unused mach_msg_type_number_t codeCnt
236)
237{
238 task_t self = current_task();
239 thread_t th_act;
240 ipc_port_t thread_port;
2d21ac55
A
241 struct proc *p;
242 kern_return_t result = MACH_MSG_SUCCESS;
243 int ux_signal = 0;
244 mach_exception_code_t ucode = 0;
245 struct uthread *ut;
b0d623f7
A
246 mach_port_name_t thread_name = CAST_MACH_PORT_TO_NAME(thread);
247 mach_port_name_t task_name = CAST_MACH_PORT_TO_NAME(task);
1c79356b 248
2d21ac55
A
249 /*
250 * Convert local thread name to global port.
251 */
1c79356b
A
252 if (MACH_PORT_VALID(thread_name) &&
253 (ipc_object_copyin(get_task_ipcspace(self), thread_name,
254 MACH_MSG_TYPE_PORT_SEND,
255 (void *) &thread_port) == MACH_MSG_SUCCESS)) {
9bccf70c 256 if (IPC_PORT_VALID(thread_port)) {
91447636 257 th_act = convert_port_to_thread(thread_port);
3e170ce0 258 ipc_port_release_send(thread_port);
1c79356b 259 } else {
91447636 260 th_act = THREAD_NULL;
1c79356b
A
261 }
262
263 /*
264 * Catch bogus ports
265 */
91447636 266 if (th_act != THREAD_NULL) {
2d21ac55 267
1c79356b
A
268 /*
269 * Convert exception to unix signal and code.
270 */
2d21ac55
A
271 ux_exception(exception, code[0], code[1], &ux_signal, &ucode);
272
273 ut = get_bsdthread_info(th_act);
316670eb 274 p = proc_findthread(th_act);
2d21ac55 275
316670eb 276 /* Can't deliver a signal without a bsd process reference */
2d21ac55
A
277 if (p == NULL) {
278 ux_signal = 0;
279 result = KERN_FAILURE;
280 }
1c79356b 281
2d21ac55
A
282 /*
283 * Stack overflow should result in a SIGSEGV signal
284 * on the alternate stack.
285 * but we have one or more guard pages after the
286 * stack top, so we would get a KERN_PROTECTION_FAILURE
287 * exception instead of KERN_INVALID_ADDRESS, resulting in
288 * a SIGBUS signal.
289 * Detect that situation and select the correct signal.
290 */
291 if (code[0] == KERN_PROTECTION_FAILURE &&
292 ux_signal == SIGBUS) {
293 user_addr_t sp, stack_min, stack_max;
294 int mask;
295 struct sigacts *ps;
296
297 sp = code[1];
316670eb 298
2d21ac55
A
299 stack_max = p->user_stack;
300 stack_min = p->user_stack - MAXSSIZ;
2d21ac55
A
301 if (sp >= stack_min &&
302 sp < stack_max) {
303 /*
304 * This is indeed a stack overflow. Deliver a
305 * SIGSEGV signal.
306 */
307 ux_signal = SIGSEGV;
308
309 /*
310 * If the thread/process is not ready to handle
311 * SIGSEGV on an alternate stack, force-deliver
312 * SIGSEGV with a SIG_DFL handler.
313 */
314 mask = sigmask(ux_signal);
315 ps = p->p_sigacts;
316 if ((p->p_sigignore & mask) ||
317 (ut->uu_sigwait & mask) ||
318 (ut->uu_sigmask & mask) ||
319 (ps->ps_sigact[SIGSEGV] == SIG_IGN) ||
320 (! (ps->ps_sigonstack & mask))) {
321 p->p_sigignore &= ~mask;
322 p->p_sigcatch &= ~mask;
323 ps->ps_sigact[SIGSEGV] = SIG_DFL;
324 ut->uu_sigwait &= ~mask;
325 ut->uu_sigmask &= ~mask;
326 }
327 }
328 }
1c79356b
A
329 /*
330 * Send signal.
331 */
0c530ab8
A
332 if (ux_signal != 0) {
333 ut->uu_exception = exception;
334 //ut->uu_code = code[0]; // filled in by threadsignal
335 ut->uu_subcode = code[1];
39037602 336 threadsignal(th_act, ux_signal, code[0], TRUE);
2d21ac55 337 }
316670eb
A
338 if (p != NULL)
339 proc_rele(p);
91447636 340 thread_deallocate(th_act);
1c79356b
A
341 }
342 else
343 result = KERN_INVALID_ARGUMENT;
344 }
345 else
346 result = KERN_INVALID_ARGUMENT;
347
348 /*
b0d623f7 349 * Delete our send rights to the task port.
1c79356b
A
350 */
351 (void)mach_port_deallocate(get_task_ipcspace(ux_handler_self), task_name);
1c79356b
A
352
353 return (result);
354}
91447636 355
1c79356b 356kern_return_t
91447636
A
357catch_exception_raise_state(
358 __unused mach_port_t exception_port,
359 __unused exception_type_t exception,
360 __unused const exception_data_t code,
361 __unused mach_msg_type_number_t codeCnt,
362 __unused int *flavor,
363 __unused const thread_state_t old_state,
364 __unused mach_msg_type_number_t old_stateCnt,
365 __unused thread_state_t new_state,
366 __unused mach_msg_type_number_t *new_stateCnt)
1c79356b
A
367{
368 return(KERN_INVALID_ARGUMENT);
369}
91447636 370
2d21ac55
A
371kern_return_t
372catch_mach_exception_raise_state(
373 __unused mach_port_t exception_port,
374 __unused exception_type_t exception,
375 __unused const mach_exception_data_t code,
376 __unused mach_msg_type_number_t codeCnt,
377 __unused int *flavor,
378 __unused const thread_state_t old_state,
379 __unused mach_msg_type_number_t old_stateCnt,
380 __unused thread_state_t new_state,
381 __unused mach_msg_type_number_t *new_stateCnt)
382{
383 return(KERN_INVALID_ARGUMENT);
384}
385
1c79356b 386kern_return_t
91447636
A
387catch_exception_raise_state_identity(
388 __unused mach_port_t exception_port,
389 __unused mach_port_t thread,
390 __unused mach_port_t task,
391 __unused exception_type_t exception,
392 __unused exception_data_t code,
393 __unused mach_msg_type_number_t codeCnt,
394 __unused int *flavor,
395 __unused thread_state_t old_state,
396 __unused mach_msg_type_number_t old_stateCnt,
397 __unused thread_state_t new_state,
398 __unused mach_msg_type_number_t *new_stateCnt)
1c79356b
A
399{
400 return(KERN_INVALID_ARGUMENT);
401}
402
2d21ac55
A
403kern_return_t
404catch_mach_exception_raise_state_identity(
405 __unused mach_port_t exception_port,
406 __unused mach_port_t thread,
407 __unused mach_port_t task,
408 __unused exception_type_t exception,
409 __unused mach_exception_data_t code,
410 __unused mach_msg_type_number_t codeCnt,
411 __unused int *flavor,
412 __unused thread_state_t old_state,
413 __unused mach_msg_type_number_t old_stateCnt,
414 __unused thread_state_t new_state,
415 __unused mach_msg_type_number_t *new_stateCnt)
416{
417 return(KERN_INVALID_ARGUMENT);
418}
419
420
1c79356b
A
421/*
422 * ux_exception translates a mach exception, code and subcode to
423 * a signal and u.u_code. Calls machine_exception (machine dependent)
424 * to attempt translation first.
425 */
426
427static
428void ux_exception(
2d21ac55
A
429 int exception,
430 mach_exception_code_t code,
431 mach_exception_subcode_t subcode,
432 int *ux_signal,
433 mach_exception_code_t *ux_code)
1c79356b
A
434{
435 /*
436 * Try machine-dependent translation first.
437 */
438 if (machine_exception(exception, code, subcode, ux_signal, ux_code))
439 return;
440
441 switch(exception) {
442
443 case EXC_BAD_ACCESS:
444 if (code == KERN_INVALID_ADDRESS)
445 *ux_signal = SIGSEGV;
446 else
447 *ux_signal = SIGBUS;
448 break;
449
450 case EXC_BAD_INSTRUCTION:
451 *ux_signal = SIGILL;
452 break;
453
454 case EXC_ARITHMETIC:
455 *ux_signal = SIGFPE;
456 break;
457
458 case EXC_EMULATION:
459 *ux_signal = SIGEMT;
460 break;
461
462 case EXC_SOFTWARE:
463 switch (code) {
464
465 case EXC_UNIX_BAD_SYSCALL:
466 *ux_signal = SIGSYS;
467 break;
468 case EXC_UNIX_BAD_PIPE:
469 *ux_signal = SIGPIPE;
470 break;
471 case EXC_UNIX_ABORT:
472 *ux_signal = SIGABRT;
473 break;
9bccf70c
A
474 case EXC_SOFT_SIGNAL:
475 *ux_signal = SIGKILL;
476 break;
1c79356b
A
477 }
478 break;
479
480 case EXC_BREAKPOINT:
481 *ux_signal = SIGTRAP;
482 break;
483 }
484}