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 |
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 |
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(sig_actthread: thread, signum: ux_signal, code, TRUE); |
181 | } |
182 | |
183 | proc_rele(p); |
184 | |
185 | return KERN_SUCCESS; |
186 | } |
187 | |