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