|
31 | 31 | #include "util/mach/bootstrap.h"
|
32 | 32 | #include "util/mach/exc_client_variants.h"
|
33 | 33 | #include "util/mach/exception_behaviors.h"
|
| 34 | +#include "util/mach/exception_ports.h" |
34 | 35 | #include "util/mach/exception_types.h"
|
35 | 36 | #include "util/mach/mach_extensions.h"
|
36 | 37 | #include "util/mach/mach_message.h"
|
@@ -188,59 +189,79 @@ kern_return_t CrashReportExceptionHandler::CatchMachException(
|
188 | 189 | }
|
189 | 190 | }
|
190 | 191 |
|
191 |
| - if (client_options.system_crash_reporter_forwarding != TriState::kDisabled && |
192 |
| - (exception == EXC_CRASH || |
193 |
| - exception == EXC_RESOURCE || |
194 |
| - exception == EXC_GUARD)) { |
195 |
| - // Don’t forward simulated exceptions such as kMachExceptionSimulated to the |
196 |
| - // system crash reporter. Only forward the types of exceptions that it would |
197 |
| - // receive under normal conditions. Although the system crash reporter is |
198 |
| - // able to deal with other exceptions including simulated ones, forwarding |
199 |
| - // them to the system crash reporter could present the system’s crash UI for |
200 |
| - // processes that haven’t actually crashed, and could result in reports not |
201 |
| - // actually associated with crashes being sent to the operating system |
202 |
| - // vendor. |
203 |
| - base::apple::ScopedMachSendRight system_crash_reporter_handler( |
204 |
| - SystemCrashReporterHandler()); |
205 |
| - if (system_crash_reporter_handler.get()) { |
206 |
| - // Make copies of mutable out parameters so that the system crash reporter |
207 |
| - // can’t influence the state returned by this method. |
208 |
| - thread_state_flavor_t flavor_forward = *flavor; |
209 |
| - mach_msg_type_number_t new_state_forward_count = *new_state_count; |
210 |
| - std::vector<natural_t> new_state_forward( |
211 |
| - new_state, new_state + new_state_forward_count); |
212 |
| - |
213 |
| - // The system crash reporter requires the behavior to be |
214 |
| - // EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES. It uses the identity |
215 |
| - // parameters but doesn’t appear to use the state parameters, including |
216 |
| - // |flavor|, and doesn’t care if they are 0 or invalid. As long as an |
217 |
| - // identity is available (checked above), any other exception behavior is |
218 |
| - // converted to what the system crash reporter wants, with the caveat that |
219 |
| - // problems may arise if the state wasn’t available and the system crash |
220 |
| - // reporter changes in the future to use it. However, normally, the state |
221 |
| - // will be available. |
222 |
| - kern_return_t kr = UniversalExceptionRaise( |
223 |
| - EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, |
224 |
| - system_crash_reporter_handler.get(), |
225 |
| - thread, |
226 |
| - task, |
227 |
| - exception, |
228 |
| - code, |
229 |
| - code_count, |
230 |
| - &flavor_forward, |
231 |
| - old_state, |
232 |
| - old_state_count, |
233 |
| - new_state_forward_count ? &new_state_forward[0] : nullptr, |
234 |
| - &new_state_forward_count); |
235 |
| - MACH_LOG_IF(WARNING, kr != KERN_SUCCESS, kr) << "UniversalExceptionRaise"; |
| 192 | + if (client_options.system_crash_reporter_forwarding != TriState::kDisabled) { |
| 193 | + if (exception == EXC_CRASH) { |
| 194 | + // For exception handlers that respond to state-carrying behaviors, when |
| 195 | + // the handler is called by the kernel (as it is normally), the kernel |
| 196 | + // will attempt to set a new thread state when the exception handler |
| 197 | + // returns successfully. Other code that mimics the kernel’s |
| 198 | + // exception-delivery semantics may implement the same or similar |
| 199 | + // behavior. In some situations, it is undesirable to set a new thread |
| 200 | + // state. If the exception handler were to return unsuccessfully, however, |
| 201 | + // the kernel would continue searching for an exception handler at a wider |
| 202 | + // (task or host) scope. This may also be undesirable. |
| 203 | + // |
| 204 | + // If such exception handlers return `MACH_RCV_PORT_DIED`, the kernel will |
| 205 | + // not set a new thread state and will also not search for another |
| 206 | + // exception handler. See 15.3 xnu-11215.84.4/osfmk/kern/exception.c. |
| 207 | + // `exception_deliver()` will only set a new thread state if the handler’s |
| 208 | + // return code was `MACH_MSG_SUCCESS` (a synonym for `KERN_SUCCESS`), and |
| 209 | + // subsequently, `exception_triage()` will not search for a new handler if |
| 210 | + // the handler’s return code was `KERN_SUCCESS` or `MACH_RCV_PORT_DIED`. |
| 211 | + // |
| 212 | + // Another effect of returning `MACH_RCV_PORT_DIED` for `EXC_CRASH` is |
| 213 | + // that an `EXC_CORPSE_NOTIFY` exception is generated. Starting with macOS |
| 214 | + // 10.15, for the system crash reporter to generate a report, |
| 215 | + // `EXC_CORPSE_NOTIFY` *must* be generated and forwarding `EXC_CRASH` (as |
| 216 | + // we do below with `EXC_RESOURCE` and pre-macOS 13 `EXC_GUARD`) is not |
| 217 | + // sufficient. Between macOS 10.11 and macOS 10.14 (inclusive), both |
| 218 | + // forwarding as below, and causing `EXC_CORPSE_NOTIFY` to be generated |
| 219 | + // are sufficient (and in fact, if we do both, two crash reports are |
| 220 | + // generated). |
| 221 | + return MACH_RCV_PORT_DIED; |
| 222 | + } |
| 223 | + if (exception == EXC_RESOURCE || exception == EXC_GUARD) { |
| 224 | + // Only forward the types of exceptions that the crash reporter would |
| 225 | + // receive under normal conditions. Otherwise, system crash reporter could |
| 226 | + // present the system’s crash UI for processes that haven’t actually |
| 227 | + // crashed, and could result in reports not actually associated with |
| 228 | + // crashes being sent to the operating system vendor. |
| 229 | + base::apple::ScopedMachSendRight system_crash_reporter_handler( |
| 230 | + SystemCrashReporterHandler()); |
| 231 | + if (system_crash_reporter_handler.get()) { |
| 232 | + // Make copies of mutable out parameters so that the system crash |
| 233 | + // reporter can’t influence the state returned by this method. |
| 234 | + thread_state_flavor_t flavor_forward = *flavor; |
| 235 | + mach_msg_type_number_t new_state_forward_count = *new_state_count; |
| 236 | + std::vector<natural_t> new_state_forward; |
| 237 | + if (new_state_forward_count) { |
| 238 | + new_state_forward.assign(new_state, |
| 239 | + new_state + new_state_forward_count); |
| 240 | + } |
| 241 | + kern_return_t kr = UniversalExceptionRaise( |
| 242 | + EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, |
| 243 | + system_crash_reporter_handler.get(), |
| 244 | + thread, |
| 245 | + task, |
| 246 | + exception, |
| 247 | + code, |
| 248 | + code_count, |
| 249 | + &flavor_forward, |
| 250 | + old_state, |
| 251 | + old_state_count, |
| 252 | + new_state_forward_count ? &new_state_forward[0] : nullptr, |
| 253 | + &new_state_forward_count); |
| 254 | + MACH_LOG_IF(WARNING, kr != KERN_SUCCESS, kr) |
| 255 | + << "UniversalExceptionRaise"; |
| 256 | + } |
236 | 257 | }
|
237 | 258 | }
|
238 | 259 |
|
239 | 260 | ExcServerCopyState(
|
240 | 261 | behavior, old_state, old_state_count, new_state, new_state_count);
|
241 | 262 |
|
242 | 263 | Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSuccess);
|
243 |
| - return ExcServerSuccessfulReturnValue(exception, behavior, false); |
| 264 | + return KERN_SUCCESS; |
244 | 265 | }
|
245 | 266 |
|
246 | 267 | } // namespace crashpad
|
0 commit comments