diff --git a/client/crashpad_client_mac.cc b/client/crashpad_client_mac.cc index 22bd538c..2fa8729b 100644 --- a/client/crashpad_client_mac.cc +++ b/client/crashpad_client_mac.cc @@ -26,6 +26,7 @@ #include "base/mac/mach_logging.h" #include "base/strings/stringprintf.h" #include "util/mac/mac_util.h" +#include "util/mach/bootstrap.h" #include "util/mach/child_port_handshake.h" #include "util/mach/exception_ports.h" #include "util/mach/mach_extensions.h" diff --git a/handler/handler_main.cc b/handler/handler_main.cc index e0a262cd..69da0f61 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -74,8 +74,8 @@ #include "handler/mac/crash_report_exception_handler.h" #include "handler/mac/exception_handler_server.h" #include "handler/mac/file_limit_annotation.h" +#include "util/mach/bootstrap.h" #include "util/mach/child_port_handshake.h" -#include "util/mach/mach_extensions.h" #include "util/posix/close_stdio.h" #include "util/posix/signals.h" #elif defined(OS_WIN) diff --git a/handler/mac/crash_report_exception_handler.cc b/handler/mac/crash_report_exception_handler.cc index 9919e955..cccf1e94 100644 --- a/handler/mac/crash_report_exception_handler.cc +++ b/handler/mac/crash_report_exception_handler.cc @@ -28,6 +28,7 @@ #include "snapshot/crashpad_info_client_options.h" #include "snapshot/mac/process_snapshot_mac.h" #include "util/file/file_writer.h" +#include "util/mach/bootstrap.h" #include "util/mach/exc_client_variants.h" #include "util/mach/exception_behaviors.h" #include "util/mach/exception_types.h" diff --git a/test/BUILD.gn b/test/BUILD.gn index 32dc298f..047c786c 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -57,14 +57,19 @@ static_library("test") { } } + if (crashpad_is_mac || crashpad_is_ios) { + sources += [ + "mac/mach_errors.cc", + "mac/mach_errors.h", + ] + } + if (crashpad_is_mac) { sources += [ "mac/dyld.cc", "mac/dyld.h", "mac/exception_swallower.cc", "mac/exception_swallower.h", - "mac/mach_errors.cc", - "mac/mach_errors.h", "mac/mach_multiprocess.cc", "mac/mach_multiprocess.h", ] diff --git a/test/mac/exception_swallower.cc b/test/mac/exception_swallower.cc index 18c5cf71..946938fb 100644 --- a/test/mac/exception_swallower.cc +++ b/test/mac/exception_swallower.cc @@ -24,6 +24,7 @@ #include "base/mac/scoped_mach_port.h" #include "base/strings/stringprintf.h" #include "handler/mac/exception_handler_server.h" +#include "util/mach/bootstrap.h" #include "util/mach/exc_server_variants.h" #include "util/mach/exception_ports.h" #include "util/mach/mach_extensions.h" diff --git a/test/mac/mach_errors.cc b/test/mac/mach_errors.cc index b68448f1..db8ed666 100644 --- a/test/mac/mach_errors.cc +++ b/test/mac/mach_errors.cc @@ -14,8 +14,6 @@ #include "test/mac/mach_errors.h" -#include - #include "base/strings/stringprintf.h" namespace { @@ -50,28 +48,5 @@ std::string MachErrorMessage(mach_error_t mach_err, const std::string& base) { FormatMachErrorNumber(mach_err).c_str()); } -std::string BootstrapErrorMessage(kern_return_t bootstrap_err, - const std::string& base) { - switch (bootstrap_err) { - case BOOTSTRAP_SUCCESS: - case BOOTSTRAP_NOT_PRIVILEGED: - case BOOTSTRAP_NAME_IN_USE: - case BOOTSTRAP_UNKNOWN_SERVICE: - case BOOTSTRAP_SERVICE_ACTIVE: - case BOOTSTRAP_BAD_COUNT: - case BOOTSTRAP_NO_MEMORY: - case BOOTSTRAP_NO_CHILDREN: - // Show known bootstrap errors in decimal because that's how they're - // defined in . - return base::StringPrintf("%s%s (%d)", - FormatBase(base).c_str(), - bootstrap_strerror(bootstrap_err), - bootstrap_err); - - default: - return MachErrorMessage(bootstrap_err, base); - } -} - } // namespace test } // namespace crashpad diff --git a/test/mac/mach_errors.h b/test/mac/mach_errors.h index 9e43ef22..0afcdadb 100644 --- a/test/mac/mach_errors.h +++ b/test/mac/mach_errors.h @@ -22,9 +22,9 @@ namespace crashpad { namespace test { -// These functions format messages in a similar way to the logging macros in -// base/mac/mach_logging.h. They exist to interoperate with gtest assertions, -// which don’t interoperate with logging but can be streamed to. +// This function formats messages in a similar way to the Mach error logging +// macros in base/mac/mach_logging.h. It exists to interoperate with gtest +// assertions, which don’t interoperate with logging but can be streamed to. // // Where non-test code could do: // MACH_CHECK(kr == KERN_SUCCESS, kr) << "vm_deallocate"; @@ -47,23 +47,6 @@ namespace test { std::string MachErrorMessage(mach_error_t mach_err, const std::string& base = std::string()); -//! \brief Formats a bootstrap error message. -//! -//! The returned string will combine the \a base string, if supplied, with a -//! textual and numeric description of the error. -//! -//! \param[in] bootstrap_err The bootstrap error code. -//! \param[in] base A string to prepend to the error description. -//! -//! \return A string of the format `"Permission denied (1100)"` if \a -//! bootstrap_err has the value `BOOTSTRAP_NOT_PRIVILEGED` on a system where -//! this is defined to be 1100. If \a base is not empty, it will be -//! prepended to this string, separated by a colon. If \a bootstrap_err is -//! not a valid bootstrap error code, it will be interpreted as a Mach error -//! code in the manner of MachErrorMessage(). -std::string BootstrapErrorMessage(kern_return_t bootstrap_err, - const std::string& base = std::string()); - } // namespace test } // namespace crashpad diff --git a/test/mac/mach_multiprocess.cc b/test/mac/mach_multiprocess.cc index f29a8b0c..59aa653e 100644 --- a/test/mac/mach_multiprocess.cc +++ b/test/mac/mach_multiprocess.cc @@ -27,6 +27,7 @@ #include "test/errors.h" #include "test/mac/mach_errors.h" #include "util/file/file_io.h" +#include "util/mach/bootstrap.h" #include "util/mach/mach_extensions.h" #include "util/mach/mach_message.h" #include "util/misc/implicit_cast.h" diff --git a/tools/mac/catch_exception_tool.cc b/tools/mac/catch_exception_tool.cc index d4dc3c12..4f40372c 100644 --- a/tools/mac/catch_exception_tool.cc +++ b/tools/mac/catch_exception_tool.cc @@ -28,6 +28,7 @@ #include "base/logging.h" #include "base/mac/mach_logging.h" #include "tools/tool_support.h" +#include "util/mach/bootstrap.h" #include "util/mach/exc_server_variants.h" #include "util/mach/exception_behaviors.h" #include "util/mach/exception_types.h" diff --git a/tools/mac/exception_port_tool.cc b/tools/mac/exception_port_tool.cc index a047e964..b9d3fdd6 100644 --- a/tools/mac/exception_port_tool.cc +++ b/tools/mac/exception_port_tool.cc @@ -30,6 +30,7 @@ #include "base/macros.h" #include "base/strings/stringprintf.h" #include "tools/tool_support.h" +#include "util/mach/bootstrap.h" #include "util/mach/exception_ports.h" #include "util/mach/mach_extensions.h" #include "util/mach/symbolic_constants_mach.h" diff --git a/util/BUILD.gn b/util/BUILD.gn index 7fe02f2b..fdd2fe14 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -248,6 +248,8 @@ static_library("util") { sources += [ "mac/xattr.cc", "mac/xattr.h", + "mach/mach_extensions.cc", + "mach/mach_extensions.h", "misc/clock_mac.cc", "misc/paths_mac.cc", "synchronization/semaphore_mac.cc", @@ -263,6 +265,8 @@ static_library("util") { "mac/mac_util.h", "mac/service_management.cc", "mac/service_management.h", + "mach/bootstrap.cc", + "mach/bootstrap.h", "mach/child_port_handshake.cc", "mach/child_port_handshake.h", "mach/child_port_server.cc", @@ -280,8 +284,6 @@ static_library("util") { "mach/exception_ports.h", "mach/exception_types.cc", "mach/exception_types.h", - "mach/mach_extensions.cc", - "mach/mach_extensions.h", "mach/mach_message.cc", "mach/mach_message.h", "mach/mach_message_server.cc", @@ -659,7 +661,10 @@ source_set("util_test") { } if (crashpad_is_mac || crashpad_is_ios) { - sources += [ "mac/xattr_test.cc" ] + sources += [ + "mac/xattr_test.cc", + "mach/mach_extensions_test.cc", + ] } if (crashpad_is_mac) { @@ -667,6 +672,7 @@ source_set("util_test") { "mac/launchd_test.mm", "mac/mac_util_test.mm", "mac/service_management_test.mm", + "mach/bootstrap_test.cc", "mach/child_port_handshake_test.cc", "mach/child_port_server_test.cc", "mach/composite_mach_message_server_test.cc", @@ -675,7 +681,6 @@ source_set("util_test") { "mach/exception_behaviors_test.cc", "mach/exception_ports_test.cc", "mach/exception_types_test.cc", - "mach/mach_extensions_test.cc", "mach/mach_message_server_test.cc", "mach/mach_message_test.cc", "mach/notify_server_test.cc", diff --git a/util/mach/bootstrap.cc b/util/mach/bootstrap.cc new file mode 100644 index 00000000..f5534372 --- /dev/null +++ b/util/mach/bootstrap.cc @@ -0,0 +1,109 @@ +// Copyright 2020 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "util/mach/bootstrap.h" + +#include +#include + +#include "base/mac/mach_logging.h" + +namespace { + +// This forms the internal implementation for BootstrapCheckIn() and +// BootstrapLookUp(), which follow the same logic aside from the routine called +// and the right type returned. + +struct BootstrapCheckInTraits { + using Type = base::mac::ScopedMachReceiveRight; + static kern_return_t Call(mach_port_t bootstrap_port, + const char* service_name, + mach_port_t* service_port) { + return bootstrap_check_in(bootstrap_port, service_name, service_port); + } + static constexpr char kName[] = "bootstrap_check_in"; +}; +constexpr char BootstrapCheckInTraits::kName[]; + +struct BootstrapLookUpTraits { + using Type = base::mac::ScopedMachSendRight; + static kern_return_t Call(mach_port_t bootstrap_port, + const char* service_name, + mach_port_t* service_port) { + return bootstrap_look_up(bootstrap_port, service_name, service_port); + } + static constexpr char kName[] = "bootstrap_look_up"; +}; +constexpr char BootstrapLookUpTraits::kName[]; + +template +typename Traits::Type BootstrapCheckInOrLookUp( + const std::string& service_name) { + // bootstrap_check_in() and bootstrap_look_up() silently truncate service + // names longer than BOOTSTRAP_MAX_NAME_LEN. This check ensures that the name + // will not be truncated. + if (service_name.size() >= BOOTSTRAP_MAX_NAME_LEN) { + LOG(ERROR) << Traits::kName << " " << service_name << ": name too long"; + return typename Traits::Type(MACH_PORT_NULL); + } + + mach_port_t service_port; + kern_return_t kr = + Traits::Call(bootstrap_port, service_name.c_str(), &service_port); + if (kr != BOOTSTRAP_SUCCESS) { + BOOTSTRAP_LOG(ERROR, kr) << Traits::kName << " " << service_name; + service_port = MACH_PORT_NULL; + } + + return typename Traits::Type(service_port); +} + +} // namespace + +namespace crashpad { + +base::mac::ScopedMachReceiveRight BootstrapCheckIn( + const std::string& service_name) { + return BootstrapCheckInOrLookUp(service_name); +} + +base::mac::ScopedMachSendRight BootstrapLookUp( + const std::string& service_name) { + base::mac::ScopedMachSendRight send( + BootstrapCheckInOrLookUp(service_name)); + + // It’s possible to race the bootstrap server when the receive right + // corresponding to the looked-up send right is destroyed immediately before + // the bootstrap_look_up() call. If the bootstrap server believes that + // |service_name| is still registered before processing the port-destroyed + // notification sent to it by the kernel, it will respond to a + // bootstrap_look_up() request with a send right that has become a dead name, + // which will be returned to the bootstrap_look_up() caller, translated into + // the caller’s IPC port name space, as the special MACH_PORT_DEAD port name. + // Check for that and return MACH_PORT_NULL in its place, as though the + // bootstrap server had fully processed the port-destroyed notification before + // responding to bootstrap_look_up(). + if (send.get() == MACH_PORT_DEAD) { + LOG(ERROR) << "bootstrap_look_up " << service_name << ": service is dead"; + send.reset(); + } + + return send; +} + +base::mac::ScopedMachSendRight SystemCrashReporterHandler() { + return BootstrapLookUp("com.apple.ReportCrash"); +} + +} // namespace crashpad diff --git a/util/mach/bootstrap.h b/util/mach/bootstrap.h new file mode 100644 index 00000000..680f5b91 --- /dev/null +++ b/util/mach/bootstrap.h @@ -0,0 +1,63 @@ +// Copyright 2020 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_UTIL_MACH_BOOTSTRAP_H_ +#define CRASHPAD_UTIL_MACH_BOOTSTRAP_H_ + +#include + +#include "base/mac/scoped_mach_port.h" + +namespace crashpad { + +//! \brief Makes a `boostrap_check_in()` call to the process’ bootstrap server. +//! +//! This function is provided to make it easier to call `bootstrap_check_in()` +//! while avoiding accidental leaks of the returned receive right. +//! +//! \param[in] service_name The service name to check in. +//! +//! \return On success, a receive right to the service port. On failure, +//! `MACH_PORT_NULL` with a message logged. +base::mac::ScopedMachReceiveRight BootstrapCheckIn( + const std::string& service_name); + +//! \brief Makes a `boostrap_look_up()` call to the process’ bootstrap server. +//! +//! This function is provided to make it easier to call `bootstrap_look_up()` +//! while avoiding accidental leaks of the returned send right. +//! +//! \param[in] service_name The service name to look up. +//! +//! \return On success, a send right to the service port. On failure, +//! `MACH_PORT_NULL` with a message logged. +base::mac::ScopedMachSendRight BootstrapLookUp(const std::string& service_name); + +//! \brief Obtains the system’s default Mach exception handler for crash-type +//! exceptions. +//! +//! This is obtained by looking up `"com.apple.ReportCrash"` with the bootstrap +//! server. The service name comes from the first launch agent loaded by +//! `launchd` with a `MachServices` entry having `ExceptionServer` set. This +//! launch agent is normally loaded from +//! `/System/Library/LaunchAgents/com.apple.ReportCrash.plist`. +//! +//! \return On success, a send right to an `exception_handler_t` corresponding +//! to the system’s default crash reporter. On failure, `MACH_PORT_NULL`, +//! with a message logged. +base::mac::ScopedMachSendRight SystemCrashReporterHandler(); + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_MACH_BOOTSTRAP_H_ diff --git a/util/mach/bootstrap_test.cc b/util/mach/bootstrap_test.cc new file mode 100644 index 00000000..44587d08 --- /dev/null +++ b/util/mach/bootstrap_test.cc @@ -0,0 +1,70 @@ +// Copyright 2020 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "util/mach/bootstrap.h" + +#include "base/mac/scoped_mach_port.h" +#include "gtest/gtest.h" +#include "util/mach/mach_extensions.h" +#include "util/misc/random_string.h" + +namespace crashpad { +namespace test { +namespace { + +TEST(Bootstrap, BootstrapCheckInAndLookUp) { + // This should always exist. + base::mac::ScopedMachSendRight report_crash( + BootstrapLookUp("com.apple.ReportCrash")); + EXPECT_NE(report_crash, kMachPortNull); + + std::string service_name = "org.chromium.crashpad.test.bootstrap_check_in."; + service_name.append(RandomString()); + + { + // The new service hasn’t checked in yet, so this should fail. + base::mac::ScopedMachSendRight send(BootstrapLookUp(service_name)); + EXPECT_EQ(send, kMachPortNull); + + // Check it in. + base::mac::ScopedMachReceiveRight receive(BootstrapCheckIn(service_name)); + EXPECT_NE(receive, kMachPortNull); + + // Now it should be possible to look up the new service. + send = BootstrapLookUp(service_name); + EXPECT_NE(send, kMachPortNull); + + // It shouldn’t be possible to check the service in while it’s active. + base::mac::ScopedMachReceiveRight receive_2(BootstrapCheckIn(service_name)); + EXPECT_EQ(receive_2, kMachPortNull); + } + + // The new service should be gone now. + base::mac::ScopedMachSendRight send(BootstrapLookUp(service_name)); + EXPECT_EQ(send, kMachPortNull); + + // It should be possible to check it in again. + base::mac::ScopedMachReceiveRight receive(BootstrapCheckIn(service_name)); + EXPECT_NE(receive, kMachPortNull); +} + +TEST(Bootstrap, SystemCrashReporterHandler) { + base::mac::ScopedMachSendRight system_crash_reporter_handler( + SystemCrashReporterHandler()); + EXPECT_TRUE(system_crash_reporter_handler.is_valid()); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/util/mach/child_port_handshake.cc b/util/mach/child_port_handshake.cc index 1891f91d..3ff9828b 100644 --- a/util/mach/child_port_handshake.cc +++ b/util/mach/child_port_handshake.cc @@ -34,6 +34,7 @@ #include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "util/file/file_io.h" +#include "util/mach/bootstrap.h" #include "util/mach/child_port.h" #include "util/mach/child_port_server.h" #include "util/mach/mach_extensions.h" diff --git a/util/mach/mach_extensions.cc b/util/mach/mach_extensions.cc index 5450ab28..9e310120 100644 --- a/util/mach/mach_extensions.cc +++ b/util/mach/mach_extensions.cc @@ -14,66 +14,14 @@ #include "util/mach/mach_extensions.h" +#include #include #include -#include #include "base/mac/mach_logging.h" +#include "build/build_config.h" #include "util/mac/mac_util.h" -namespace { - -// This forms the internal implementation for BootstrapCheckIn() and -// BootstrapLookUp(), which follow the same logic aside from the routine called -// and the right type returned. - -struct BootstrapCheckInTraits { - using Type = base::mac::ScopedMachReceiveRight; - static kern_return_t Call(mach_port_t bootstrap_port, - const char* service_name, - mach_port_t* service_port) { - return bootstrap_check_in(bootstrap_port, service_name, service_port); - } - static constexpr char kName[] = "bootstrap_check_in"; -}; -constexpr char BootstrapCheckInTraits::kName[]; - -struct BootstrapLookUpTraits { - using Type = base::mac::ScopedMachSendRight; - static kern_return_t Call(mach_port_t bootstrap_port, - const char* service_name, - mach_port_t* service_port) { - return bootstrap_look_up(bootstrap_port, service_name, service_port); - } - static constexpr char kName[] = "bootstrap_look_up"; -}; -constexpr char BootstrapLookUpTraits::kName[]; - -template -typename Traits::Type BootstrapCheckInOrLookUp( - const std::string& service_name) { - // bootstrap_check_in() and bootstrap_look_up() silently truncate service - // names longer than BOOTSTRAP_MAX_NAME_LEN. This check ensures that the name - // will not be truncated. - if (service_name.size() >= BOOTSTRAP_MAX_NAME_LEN) { - LOG(ERROR) << Traits::kName << " " << service_name << ": name too long"; - return typename Traits::Type(MACH_PORT_NULL); - } - - mach_port_t service_port; - kern_return_t kr = Traits::Call(bootstrap_port, - service_name.c_str(), - &service_port); - if (kr != BOOTSTRAP_SUCCESS) { - BOOTSTRAP_LOG(ERROR, kr) << Traits::kName << " " << service_name; - service_port = MACH_PORT_NULL; - } - - return typename Traits::Type(service_port); -} - -} // namespace - namespace crashpad { thread_t MachThreadSelf() { @@ -97,7 +45,12 @@ exception_mask_t ExcMaskAll() { // 10.9.4 xnu-2422.110.17/osfmk/mach/ipc_host.c and // xnu-2422.110.17/osfmk/mach/ipc_tt.c. -#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9 +#if defined(OS_IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 +// iOS 7 ≅ macOS 10.9. +#error This code was not ported to iOS versions older than 7 +#endif + +#if !defined(OS_IOS) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9 const int mac_os_x_minor_version = MacOSXMinorVersion(); #endif @@ -114,7 +67,7 @@ exception_mask_t ExcMaskAll() { EXC_MASK_MACH_SYSCALL | EXC_MASK_RPC_ALERT | EXC_MASK_MACHINE; -#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8 +#if !defined(OS_IOS) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8 if (mac_os_x_minor_version < 8) { return kExcMaskAll_10_6; } @@ -124,7 +77,7 @@ exception_mask_t ExcMaskAll() { // xnu-2050.48.11/osfmk/mach/exception_types.h. constexpr exception_mask_t kExcMaskAll_10_8 = kExcMaskAll_10_6 | EXC_MASK_RESOURCE; -#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9 +#if !defined(OS_IOS) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9 if (mac_os_x_minor_version < 9) { return kExcMaskAll_10_8; } @@ -139,7 +92,12 @@ exception_mask_t ExcMaskAll() { exception_mask_t ExcMaskValid() { const exception_mask_t kExcMaskValid_10_6 = ExcMaskAll() | EXC_MASK_CRASH; -#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11 +#if defined(OS_IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0 +// iOS 9 ≅ macOS 10.11. +#error This code was not ported to iOS versions older than 9 +#endif + +#if !defined(OS_IOS) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11 if (MacOSXMinorVersion() < 11) { return kExcMaskValid_10_6; } @@ -151,37 +109,4 @@ exception_mask_t ExcMaskValid() { return kExcMaskValid_10_11; } -base::mac::ScopedMachReceiveRight BootstrapCheckIn( - const std::string& service_name) { - return BootstrapCheckInOrLookUp(service_name); -} - -base::mac::ScopedMachSendRight BootstrapLookUp( - const std::string& service_name) { - base::mac::ScopedMachSendRight send( - BootstrapCheckInOrLookUp(service_name)); - - // It’s possible to race the bootstrap server when the receive right - // corresponding to the looked-up send right is destroyed immediately before - // the bootstrap_look_up() call. If the bootstrap server believes that - // |service_name| is still registered before processing the port-destroyed - // notification sent to it by the kernel, it will respond to a - // bootstrap_look_up() request with a send right that has become a dead name, - // which will be returned to the bootstrap_look_up() caller, translated into - // the caller’s IPC port name space, as the special MACH_PORT_DEAD port name. - // Check for that and return MACH_PORT_NULL in its place, as though the - // bootstrap server had fully processed the port-destroyed notification before - // responding to bootstrap_look_up(). - if (send.get() == MACH_PORT_DEAD) { - LOG(ERROR) << "bootstrap_look_up " << service_name << ": service is dead"; - send.reset(); - } - - return send; -} - -base::mac::ScopedMachSendRight SystemCrashReporterHandler() { - return BootstrapLookUp("com.apple.ReportCrash"); -} - } // namespace crashpad diff --git a/util/mach/mach_extensions.h b/util/mach/mach_extensions.h index 25e401c2..9247ce94 100644 --- a/util/mach/mach_extensions.h +++ b/util/mach/mach_extensions.h @@ -17,10 +17,6 @@ #include -#include - -#include "base/mac/scoped_mach_port.h" - namespace crashpad { //! \brief `MACH_PORT_NULL` with the correct type for a Mach port, @@ -119,43 +115,6 @@ exception_mask_t ExcMaskAll(); //! support is present. exception_mask_t ExcMaskValid(); -//! \brief Makes a `boostrap_check_in()` call to the process’ bootstrap server. -//! -//! This function is provided to make it easier to call `bootstrap_check_in()` -//! while avoiding accidental leaks of the returned receive right. -//! -//! \param[in] service_name The service name to check in. -//! -//! \return On success, a receive right to the service port. On failure, -//! `MACH_PORT_NULL` with a message logged. -base::mac::ScopedMachReceiveRight BootstrapCheckIn( - const std::string& service_name); - -//! \brief Makes a `boostrap_look_up()` call to the process’ bootstrap server. -//! -//! This function is provided to make it easier to call `bootstrap_look_up()` -//! while avoiding accidental leaks of the returned send right. -//! -//! \param[in] service_name The service name to look up. -//! -//! \return On success, a send right to the service port. On failure, -//! `MACH_PORT_NULL` with a message logged. -base::mac::ScopedMachSendRight BootstrapLookUp(const std::string& service_name); - -//! \brief Obtains the system’s default Mach exception handler for crash-type -//! exceptions. -//! -//! This is obtained by looking up `"com.apple.ReportCrash"` with the bootstrap -//! server. The service name comes from the first launch agent loaded by -//! `launchd` with a `MachServices` entry having `ExceptionServer` set. This -//! launch agent is normally loaded from -//! `/System/Library/LaunchAgents/com.apple.ReportCrash.plist`. -//! -//! \return On success, a send right to an `exception_handler_t` corresponding -//! to the system’s default crash reporter. On failure, `MACH_PORT_NULL`, -//! with a message logged. -base::mac::ScopedMachSendRight SystemCrashReporterHandler(); - } // namespace crashpad #endif // CRASHPAD_UTIL_MACH_MACH_EXTENSIONS_H_ diff --git a/util/mach/mach_extensions_test.cc b/util/mach/mach_extensions_test.cc index 1c5b368c..748e0aa5 100644 --- a/util/mach/mach_extensions_test.cc +++ b/util/mach/mach_extensions_test.cc @@ -15,10 +15,10 @@ #include "util/mach/mach_extensions.h" #include "base/mac/scoped_mach_port.h" +#include "build/build_config.h" #include "gtest/gtest.h" #include "test/mac/mach_errors.h" #include "util/mac/mac_util.h" -#include "util/misc/random_string.h" namespace crashpad { namespace test { @@ -80,6 +80,11 @@ TEST(MachExtensions, ExcMaskAll) { EXPECT_FALSE(exc_mask_all & EXC_MASK_CRASH); EXPECT_FALSE(exc_mask_all & EXC_MASK_CORPSE_NOTIFY); +#if defined(OS_IOS) + // Assume at least iOS 7 (≅ macOS 10.9). + EXPECT_TRUE(exc_mask_all & EXC_MASK_RESOURCE); + EXPECT_TRUE(exc_mask_all & EXC_MASK_GUARD); +#else // OS_IOS const int mac_os_x_minor_version = MacOSXMinorVersion(); if (mac_os_x_minor_version >= 8) { EXPECT_TRUE(exc_mask_all & EXC_MASK_RESOURCE); @@ -92,6 +97,7 @@ TEST(MachExtensions, ExcMaskAll) { } else { EXPECT_FALSE(exc_mask_all & EXC_MASK_GUARD); } +#endif // OS_IOS // Bit 0 should not be set. EXPECT_FALSE(ExcMaskAll() & 1); @@ -106,6 +112,12 @@ TEST(MachExtensions, ExcMaskValid) { EXPECT_TRUE(exc_mask_valid & EXC_MASK_CRASH); +#if defined(OS_IOS) + // Assume at least iOS 9 (≅ macOS 10.11). + EXPECT_TRUE(exc_mask_valid & EXC_MASK_RESOURCE); + EXPECT_TRUE(exc_mask_valid & EXC_MASK_GUARD); + EXPECT_TRUE(exc_mask_valid & EXC_MASK_CORPSE_NOTIFY); +#else // OS_IOS const int mac_os_x_minor_version = MacOSXMinorVersion(); if (mac_os_x_minor_version >= 8) { EXPECT_TRUE(exc_mask_valid & EXC_MASK_RESOURCE); @@ -124,6 +136,7 @@ TEST(MachExtensions, ExcMaskValid) { } else { EXPECT_FALSE(exc_mask_valid & EXC_MASK_CORPSE_NOTIFY); } +#endif // OS_IOS // Bit 0 should not be set. EXPECT_FALSE(ExcMaskValid() & 1); @@ -132,48 +145,6 @@ TEST(MachExtensions, ExcMaskValid) { EXPECT_TRUE(ExcMaskValid() & ~ExcMaskAll()); } -TEST(MachExtensions, BootstrapCheckInAndLookUp) { - // This should always exist. - base::mac::ScopedMachSendRight - report_crash(BootstrapLookUp("com.apple.ReportCrash")); - EXPECT_NE(report_crash, kMachPortNull); - - std::string service_name = "org.chromium.crashpad.test.bootstrap_check_in."; - service_name.append(RandomString()); - - { - // The new service hasn’t checked in yet, so this should fail. - base::mac::ScopedMachSendRight send(BootstrapLookUp(service_name)); - EXPECT_EQ(send, kMachPortNull); - - // Check it in. - base::mac::ScopedMachReceiveRight receive(BootstrapCheckIn(service_name)); - EXPECT_NE(receive, kMachPortNull); - - // Now it should be possible to look up the new service. - send = BootstrapLookUp(service_name); - EXPECT_NE(send, kMachPortNull); - - // It shouldn’t be possible to check the service in while it’s active. - base::mac::ScopedMachReceiveRight receive_2(BootstrapCheckIn(service_name)); - EXPECT_EQ(receive_2, kMachPortNull); - } - - // The new service should be gone now. - base::mac::ScopedMachSendRight send(BootstrapLookUp(service_name)); - EXPECT_EQ(send, kMachPortNull); - - // It should be possible to check it in again. - base::mac::ScopedMachReceiveRight receive(BootstrapCheckIn(service_name)); - EXPECT_NE(receive, kMachPortNull); -} - -TEST(MachExtensions, SystemCrashReporterHandler) { - base::mac::ScopedMachSendRight - system_crash_reporter_handler(SystemCrashReporterHandler()); - EXPECT_TRUE(system_crash_reporter_handler.is_valid()); -} - } // namespace } // namespace test } // namespace crashpad