ios: Build four more Mach message and exception utilities

This enables the following code in util/mach on iOS:
 - exception_behaviors.{cc,h}
 - exception_ports.{cc,h}
 - mach_message.{cc,h}
 - mach_message_server.{cc,h}

Only the ExceptionBehaviors and MachMessage tests are built, because the
other two are tested by multiprocess tests that won’t run on iOS.

The AuditPIDFromMachMessageTrailer function from mach_message.h is
excluded on iOS because it relies on <bsm/libbsm.h>, which is broken on
iOS: it depends on <bsm/audit_record.h>, which is missing from the SDK.
Additionally, the BSM function that Crashpad uses, audit_token_to_au32,
is marked as unavailable on iOS. Crashpad uses it on macOS to
authenticate Mach messages sent by other processes, but this is moot on
iOS.

Bug: crashpad:31
Change-Id: I5ebc4b80543989b9cd0b85b82eb4b3ff98c44e6c
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2155086
Reviewed-by: Justin Cohen <justincohen@chromium.org>
Commit-Queue: Mark Mentovai <mark@chromium.org>
This commit is contained in:
Mark Mentovai 2020-04-17 17:45:18 -04:00 committed by Commit Bot
parent 8dbbaff2e1
commit 4cb79941fc
4 changed files with 116 additions and 103 deletions

View File

@ -254,8 +254,16 @@ static_library("util") {
sources += [ sources += [
"mac/xattr.cc", "mac/xattr.cc",
"mac/xattr.h", "mac/xattr.h",
"mach/exception_behaviors.cc",
"mach/exception_behaviors.h",
"mach/exception_ports.cc",
"mach/exception_ports.h",
"mach/mach_extensions.cc", "mach/mach_extensions.cc",
"mach/mach_extensions.h", "mach/mach_extensions.h",
"mach/mach_message.cc",
"mach/mach_message.h",
"mach/mach_message_server.cc",
"mach/mach_message_server.h",
"misc/clock_mac.cc", "misc/clock_mac.cc",
"misc/paths_mac.cc", "misc/paths_mac.cc",
"synchronization/semaphore_mac.cc", "synchronization/semaphore_mac.cc",
@ -284,16 +292,8 @@ static_library("util") {
"mach/exc_client_variants.h", "mach/exc_client_variants.h",
"mach/exc_server_variants.cc", "mach/exc_server_variants.cc",
"mach/exc_server_variants.h", "mach/exc_server_variants.h",
"mach/exception_behaviors.cc",
"mach/exception_behaviors.h",
"mach/exception_ports.cc",
"mach/exception_ports.h",
"mach/exception_types.cc", "mach/exception_types.cc",
"mach/exception_types.h", "mach/exception_types.h",
"mach/mach_message.cc",
"mach/mach_message.h",
"mach/mach_message_server.cc",
"mach/mach_message_server.h",
"mach/notify_server.cc", "mach/notify_server.cc",
"mach/notify_server.h", "mach/notify_server.h",
"mach/scoped_task_suspend.cc", "mach/scoped_task_suspend.cc",
@ -518,9 +518,7 @@ static_library("util") {
if (crashpad_is_mac || crashpad_is_ios) { if (crashpad_is_mac || crashpad_is_ios) {
include_dirs += [ "$root_build_dir/gen" ] include_dirs += [ "$root_build_dir/gen" ]
deps += [ deps += [ ":mig_output" ]
":mig_output",
]
} }
if (crashpad_is_mac) { if (crashpad_is_mac) {
@ -530,9 +528,7 @@ static_library("util") {
"Foundation.framework", "Foundation.framework",
"IOKit.framework", "IOKit.framework",
] ]
deps += [ deps += [ "../third_party/apple_cf:apple_cf" ]
"../third_party/apple_cf:apple_cf",
]
} }
if (crashpad_is_win) { if (crashpad_is_win) {
@ -674,7 +670,9 @@ source_set("util_test") {
if (crashpad_is_mac || crashpad_is_ios) { if (crashpad_is_mac || crashpad_is_ios) {
sources += [ sources += [
"mac/xattr_test.cc", "mac/xattr_test.cc",
"mach/exception_behaviors_test.cc",
"mach/mach_extensions_test.cc", "mach/mach_extensions_test.cc",
"mach/mach_message_test.cc",
] ]
} }
@ -689,11 +687,9 @@ source_set("util_test") {
"mach/composite_mach_message_server_test.cc", "mach/composite_mach_message_server_test.cc",
"mach/exc_client_variants_test.cc", "mach/exc_client_variants_test.cc",
"mach/exc_server_variants_test.cc", "mach/exc_server_variants_test.cc",
"mach/exception_behaviors_test.cc",
"mach/exception_ports_test.cc", "mach/exception_ports_test.cc",
"mach/exception_types_test.cc", "mach/exception_types_test.cc",
"mach/mach_message_server_test.cc", "mach/mach_message_server_test.cc",
"mach/mach_message_test.cc",
"mach/notify_server_test.cc", "mach/notify_server_test.cc",
"mach/scoped_task_suspend_test.cc", "mach/scoped_task_suspend_test.cc",
"mach/symbolic_constants_mach_test.cc", "mach/symbolic_constants_mach_test.cc",

View File

@ -15,7 +15,6 @@
#include "util/mach/mach_message.h" #include "util/mach/mach_message.h"
#include <AvailabilityMacros.h> #include <AvailabilityMacros.h>
#include <bsm/libbsm.h>
#include <limits> #include <limits>
@ -24,6 +23,10 @@
#include "util/misc/clock.h" #include "util/misc/clock.h"
#include "util/misc/implicit_cast.h" #include "util/misc/implicit_cast.h"
#if !defined(OS_IOS)
#include <bsm/libbsm.h>
#endif // !OS_IOS
namespace crashpad { namespace crashpad {
namespace { namespace {
@ -217,38 +220,6 @@ const mach_msg_trailer_t* MachMessageTrailerFromHeader(
return reinterpret_cast<const mach_msg_trailer_t*>(trailer_address); return reinterpret_cast<const mach_msg_trailer_t*>(trailer_address);
} }
pid_t AuditPIDFromMachMessageTrailer(const mach_msg_trailer_t* trailer) {
if (trailer->msgh_trailer_type != MACH_MSG_TRAILER_FORMAT_0) {
LOG(ERROR) << "unexpected msgh_trailer_type " << trailer->msgh_trailer_type;
return -1;
}
if (trailer->msgh_trailer_size <
REQUESTED_TRAILER_SIZE(kMachMessageReceiveAuditTrailer)) {
LOG(ERROR) << "small msgh_trailer_size " << trailer->msgh_trailer_size;
return -1;
}
const mach_msg_audit_trailer_t* audit_trailer =
reinterpret_cast<const mach_msg_audit_trailer_t*>(trailer);
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8
pid_t audit_pid;
audit_token_to_au32(audit_trailer->msgh_audit,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
&audit_pid,
nullptr,
nullptr);
#else
pid_t audit_pid = audit_token_to_pid(audit_trailer->msgh_audit);
#endif
return audit_pid;
}
bool MachMessageDestroyReceivedPort(mach_port_t port, bool MachMessageDestroyReceivedPort(mach_port_t port,
mach_msg_type_name_t port_right_type) { mach_msg_type_name_t port_right_type) {
// This implements a subset of 10.10.5 // This implements a subset of 10.10.5
@ -282,4 +253,40 @@ bool MachMessageDestroyReceivedPort(mach_port_t port,
} }
} }
#if !defined(OS_IOS)
pid_t AuditPIDFromMachMessageTrailer(const mach_msg_trailer_t* trailer) {
if (trailer->msgh_trailer_type != MACH_MSG_TRAILER_FORMAT_0) {
LOG(ERROR) << "unexpected msgh_trailer_type " << trailer->msgh_trailer_type;
return -1;
}
if (trailer->msgh_trailer_size <
REQUESTED_TRAILER_SIZE(kMachMessageReceiveAuditTrailer)) {
LOG(ERROR) << "small msgh_trailer_size " << trailer->msgh_trailer_size;
return -1;
}
const mach_msg_audit_trailer_t* audit_trailer =
reinterpret_cast<const mach_msg_audit_trailer_t*>(trailer);
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8
pid_t audit_pid;
audit_token_to_au32(audit_trailer->msgh_audit,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
&audit_pid,
nullptr,
nullptr);
#else
pid_t audit_pid = audit_token_to_pid(audit_trailer->msgh_audit);
#endif
return audit_pid;
}
#endif // !OS_IOS
} // namespace crashpad } // namespace crashpad

View File

@ -19,6 +19,8 @@
#include <stdint.h> #include <stdint.h>
#include <sys/types.h> #include <sys/types.h>
#include "build/build_config.h"
namespace crashpad { namespace crashpad {
//! \brief A Mach message option specifying that an audit trailer should be //! \brief A Mach message option specifying that an audit trailer should be
@ -166,6 +168,23 @@ void SetMIGReplyError(mach_msg_header_t* out_header, kern_return_t error);
const mach_msg_trailer_t* MachMessageTrailerFromHeader( const mach_msg_trailer_t* MachMessageTrailerFromHeader(
const mach_msg_header_t* header); const mach_msg_header_t* header);
//! \brief Destroys or deallocates a Mach port received in a Mach message.
//!
//! This function disposes of port rights received in a Mach message. Receive
//! rights will be destroyed with `mach_port_mod_refs()`. Send and send-once
//! rights will be deallocated with `mach_port_deallocate()`.
//!
//! \param[in] port The port to destroy or deallocate.
//! \param[in] port_right_type The right type held for \a port:
//! `MACH_MSG_TYPE_PORT_RECEIVE`, `MACH_MSG_TYPE_PORT_SEND`, or
//! `MACH_MSG_TYPE_PORT_SEND_ONCE`.
//!
//! \return `true` on success, or `false` on failure with a message logged.
bool MachMessageDestroyReceivedPort(mach_port_t port,
mach_msg_type_name_t port_right_type);
#if !defined(OS_IOS) || DOXYGEN
//! \brief Returns the process ID of a Mach messages sender from its audit //! \brief Returns the process ID of a Mach messages sender from its audit
//! trailer. //! trailer.
//! //!
@ -182,20 +201,7 @@ const mach_msg_trailer_t* MachMessageTrailerFromHeader(
//! audit information. //! audit information.
pid_t AuditPIDFromMachMessageTrailer(const mach_msg_trailer_t* trailer); pid_t AuditPIDFromMachMessageTrailer(const mach_msg_trailer_t* trailer);
//! \brief Destroys or deallocates a Mach port received in a Mach message. #endif // !OS_IOS
//!
//! This function disposes of port rights received in a Mach message. Receive
//! rights will be destroyed with `mach_port_mod_refs()`. Send and send-once
//! rights will be deallocated with `mach_port_deallocate()`.
//!
//! \param[in] port The port to destroy or deallocate.
//! \param[in] port_right_type The right type held for \a port:
//! `MACH_MSG_TYPE_PORT_RECEIVE`, `MACH_MSG_TYPE_PORT_SEND`, or
//! `MACH_MSG_TYPE_PORT_SEND_ONCE`.
//!
//! \return `true` on success, or `false` on failure with a message logged.
bool MachMessageDestroyReceivedPort(mach_port_t port,
mach_msg_type_name_t port_right_type);
} // namespace crashpad } // namespace crashpad

View File

@ -109,46 +109,6 @@ TEST(MachMessage, MachMessageTrailerFromHeader) {
EXPECT_EQ(MachMessageTrailerFromHeader(&test.receive), &test.receive.trailer); EXPECT_EQ(MachMessageTrailerFromHeader(&test.receive), &test.receive.trailer);
} }
TEST(MachMessage, AuditPIDFromMachMessageTrailer) {
base::mac::ScopedMachReceiveRight port(NewMachPort(MACH_PORT_RIGHT_RECEIVE));
ASSERT_NE(port, kMachPortNull);
mach_msg_empty_send_t send = {};
send.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND_ONCE, 0);
send.header.msgh_size = sizeof(send);
send.header.msgh_remote_port = port.get();
mach_msg_return_t mr =
MachMessageWithDeadline(&send.header,
MACH_SEND_MSG,
0,
MACH_PORT_NULL,
kMachMessageDeadlineNonblocking,
MACH_PORT_NULL,
false);
ASSERT_EQ(mr, MACH_MSG_SUCCESS)
<< MachErrorMessage(mr, "MachMessageWithDeadline send");
struct EmptyReceiveMessageWithAuditTrailer : public mach_msg_empty_send_t {
union {
mach_msg_trailer_t trailer;
mach_msg_audit_trailer_t audit_trailer;
};
};
EmptyReceiveMessageWithAuditTrailer receive;
mr = MachMessageWithDeadline(&receive.header,
MACH_RCV_MSG | kMachMessageReceiveAuditTrailer,
sizeof(receive),
port.get(),
kMachMessageDeadlineNonblocking,
MACH_PORT_NULL,
false);
ASSERT_EQ(mr, MACH_MSG_SUCCESS)
<< MachErrorMessage(mr, "MachMessageWithDeadline receive");
EXPECT_EQ(AuditPIDFromMachMessageTrailer(&receive.trailer), getpid());
}
TEST(MachMessage, MachMessageDestroyReceivedPort) { TEST(MachMessage, MachMessageDestroyReceivedPort) {
mach_port_t port = NewMachPort(MACH_PORT_RIGHT_RECEIVE); mach_port_t port = NewMachPort(MACH_PORT_RIGHT_RECEIVE);
ASSERT_NE(port, kMachPortNull); ASSERT_NE(port, kMachPortNull);
@ -198,6 +158,50 @@ TEST(MachMessage, MachMessageDestroyReceivedPort) {
EXPECT_TRUE(MachMessageDestroyReceivedPort(port, MACH_MSG_TYPE_PORT_SEND)); EXPECT_TRUE(MachMessageDestroyReceivedPort(port, MACH_MSG_TYPE_PORT_SEND));
} }
#if !defined(OS_IOS)
TEST(MachMessage, AuditPIDFromMachMessageTrailer) {
base::mac::ScopedMachReceiveRight port(NewMachPort(MACH_PORT_RIGHT_RECEIVE));
ASSERT_NE(port, kMachPortNull);
mach_msg_empty_send_t send = {};
send.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND_ONCE, 0);
send.header.msgh_size = sizeof(send);
send.header.msgh_remote_port = port.get();
mach_msg_return_t mr =
MachMessageWithDeadline(&send.header,
MACH_SEND_MSG,
0,
MACH_PORT_NULL,
kMachMessageDeadlineNonblocking,
MACH_PORT_NULL,
false);
ASSERT_EQ(mr, MACH_MSG_SUCCESS)
<< MachErrorMessage(mr, "MachMessageWithDeadline send");
struct EmptyReceiveMessageWithAuditTrailer : public mach_msg_empty_send_t {
union {
mach_msg_trailer_t trailer;
mach_msg_audit_trailer_t audit_trailer;
};
};
EmptyReceiveMessageWithAuditTrailer receive;
mr = MachMessageWithDeadline(&receive.header,
MACH_RCV_MSG | kMachMessageReceiveAuditTrailer,
sizeof(receive),
port.get(),
kMachMessageDeadlineNonblocking,
MACH_PORT_NULL,
false);
ASSERT_EQ(mr, MACH_MSG_SUCCESS)
<< MachErrorMessage(mr, "MachMessageWithDeadline receive");
EXPECT_EQ(AuditPIDFromMachMessageTrailer(&receive.trailer), getpid());
}
#endif // !OS_IOS
} // namespace } // namespace
} // namespace test } // namespace test
} // namespace crashpad } // namespace crashpad