mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 22:26:06 +00:00
ios: Split bootstrap out from mach_extensions
mach_extensions is sensible on iOS, but bootstrap is not available outside of macOS. To allow mach_extensions to be used cleanly on iOS, the bootstrap code is moved into its own macOS-specific file. Bug: crashpad:31 Change-Id: I7bf9d5194253b563954a1e55fbf67a16f686e8ff Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2154529 Reviewed-by: Justin Cohen <justincohen@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
122a400d7b
commit
ba24acb86c
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -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",
|
||||
]
|
||||
|
@ -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"
|
||||
|
@ -14,8 +14,6 @@
|
||||
|
||||
#include "test/mac/mach_errors.h"
|
||||
|
||||
#include <servers/bootstrap.h>
|
||||
|
||||
#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 <servers/bootstrap.h>.
|
||||
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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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",
|
||||
|
109
util/mach/bootstrap.cc
Normal file
109
util/mach/bootstrap.cc
Normal file
@ -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 <mach/mach.h>
|
||||
#include <servers/bootstrap.h>
|
||||
|
||||
#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>
|
||||
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<BootstrapCheckInTraits>(service_name);
|
||||
}
|
||||
|
||||
base::mac::ScopedMachSendRight BootstrapLookUp(
|
||||
const std::string& service_name) {
|
||||
base::mac::ScopedMachSendRight send(
|
||||
BootstrapCheckInOrLookUp<BootstrapLookUpTraits>(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
|
63
util/mach/bootstrap.h
Normal file
63
util/mach/bootstrap.h
Normal file
@ -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 <string>
|
||||
|
||||
#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_
|
70
util/mach/bootstrap_test.cc
Normal file
70
util/mach/bootstrap_test.cc
Normal file
@ -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
|
@ -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"
|
||||
|
@ -14,66 +14,14 @@
|
||||
|
||||
#include "util/mach/mach_extensions.h"
|
||||
|
||||
#include <Availability.h>
|
||||
#include <AvailabilityMacros.h>
|
||||
#include <pthread.h>
|
||||
#include <servers/bootstrap.h>
|
||||
|
||||
#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>
|
||||
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<BootstrapCheckInTraits>(service_name);
|
||||
}
|
||||
|
||||
base::mac::ScopedMachSendRight BootstrapLookUp(
|
||||
const std::string& service_name) {
|
||||
base::mac::ScopedMachSendRight send(
|
||||
BootstrapCheckInOrLookUp<BootstrapLookUpTraits>(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
|
||||
|
@ -17,10 +17,6 @@
|
||||
|
||||
#include <mach/mach.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#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_
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user