]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
d9a64523 | 2 | * Copyright (c) 2000-2017 Apple Inc. All rights reserved. |
5d5c5d0d | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
d9a64523 | 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. | |
d9a64523 | 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. | |
d9a64523 | 17 | * |
2d21ac55 A |
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. | |
d9a64523 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b | 27 | */ |
d9a64523 | 28 | /* |
1c79356b A |
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 | ||
1c79356b A |
35 | #include <sys/param.h> |
36 | ||
37 | #include <mach/boolean.h> | |
38 | #include <mach/exception.h> | |
39 | #include <mach/kern_return.h> | |
1c79356b A |
40 | |
41 | #include <sys/proc.h> | |
42 | #include <sys/user.h> | |
43 | #include <sys/systm.h> | |
d9a64523 | 44 | #include <sys/vmparam.h> /* MAXSSIZ */ |
91447636 | 45 | |
d9a64523 | 46 | #include <sys/ux_exception.h> |
2d21ac55 | 47 | |
1c79356b | 48 | /* |
d9a64523 A |
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. | |
1c79356b | 54 | */ |
d9a64523 A |
55 | static int |
56 | ux_exception(int exception, | |
0a7de745 A |
57 | mach_exception_code_t code, |
58 | mach_exception_subcode_t subcode) | |
1c79356b | 59 | { |
d9a64523 A |
60 | int machine_signal = 0; |
61 | ||
62 | /* Try machine-dependent translation first. */ | |
0a7de745 | 63 | if ((machine_signal = machine_exception(exception, code, subcode)) != 0) { |
d9a64523 | 64 | return machine_signal; |
0a7de745 | 65 | } |
d9a64523 | 66 | |
0a7de745 A |
67 | switch (exception) { |
68 | case EXC_BAD_ACCESS: | |
69 | if (code == KERN_INVALID_ADDRESS) { | |
70 | return SIGSEGV; | |
71 | } else { | |
72 | return SIGBUS; | |
73 | } | |
d9a64523 | 74 | |
0a7de745 A |
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; | |
1c79356b | 99 | } |
1c79356b | 100 | |
d9a64523 | 101 | return 0; |
1c79356b A |
102 | } |
103 | ||
d9a64523 A |
104 | /* |
105 | * Sends the corresponding UNIX signal to a thread that has triggered a Mach exception. | |
106 | */ | |
1c79356b | 107 | kern_return_t |
d9a64523 | 108 | handle_ux_exception(thread_t thread, |
0a7de745 A |
109 | int exception, |
110 | mach_exception_code_t code, | |
111 | mach_exception_subcode_t subcode) | |
1c79356b | 112 | { |
d9a64523 A |
113 | /* Returns +1 proc reference */ |
114 | proc_t p = proc_findthread(thread); | |
2d21ac55 | 115 | |
d9a64523 | 116 | /* Can't deliver a signal without a bsd process reference */ |
0a7de745 | 117 | if (p == NULL) { |
d9a64523 | 118 | return KERN_FAILURE; |
0a7de745 | 119 | } |
2d21ac55 | 120 | |
d9a64523 A |
121 | /* Translate exception and code to signal type */ |
122 | int ux_signal = ux_exception(exception, code, subcode); | |
2d21ac55 | 123 | |
d9a64523 | 124 | uthread_t ut = get_bsdthread_info(thread); |
1c79356b | 125 | |
2d21ac55 | 126 | /* |
d9a64523 A |
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. | |
2d21ac55 | 134 | */ |
d9a64523 A |
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 | (ps->ps_sigact[SIGSEGV] == SIG_IGN) || | |
0a7de745 | 159 | (!(ps->ps_sigonstack & mask))) { |
d9a64523 A |
160 | p->p_sigignore &= ~mask; |
161 | p->p_sigcatch &= ~mask; | |
162 | ps->ps_sigact[SIGSEGV] = SIG_DFL; | |
163 | ut->uu_sigwait &= ~mask; | |
164 | ut->uu_sigmask &= ~mask; | |
165 | } | |
166 | } | |
1c79356b A |
167 | } |
168 | ||
d9a64523 A |
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); | |
1c79356b | 175 | } |
1c79356b | 176 | |
d9a64523 | 177 | proc_rele(p); |
1c79356b | 178 | |
d9a64523 | 179 | return KERN_SUCCESS; |
1c79356b | 180 | } |