From 0437bc53b660a43027dd938ac9752407bf705ebc Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Mon, 1 Dec 2014 16:06:56 -0500 Subject: [PATCH] Pass Mach message trailers to server handler functions. TEST=util_test ChildPortServer.*:ExcServerVariants.*:MachMessageUtil.* R=rsesek@chromium.org Review URL: https://codereview.chromium.org/755313004 --- client/simulate_crash_mac_test.cc | 1 + .../mach_o_image_annotations_reader_test.cc | 1 + tools/catch_exception_tool.cc | 1 + util/mach/child_port_handshake.cc | 1 + util/mach/child_port_handshake.h | 1 + util/mach/child_port_server.cc | 4 + util/mach/child_port_server.h | 2 + util/mach/child_port_server_test.cc | 9 +- util/mach/exc_client_variants_test.cc | 1 + util/mach/exc_server_variants.cc | 34 +++++- util/mach/exc_server_variants.h | 31 ++++- util/mach/exc_server_variants_test.cc | 109 +++++++++++++----- util/mach/exception_ports_test.cc | 1 + util/mach/mach_message_server.cc | 12 +- util/mach/mach_message_util.cc | 7 ++ util/mach/mach_message_util.h | 14 +++ util/mach/mach_message_util_test.cc | 23 ++++ 17 files changed, 206 insertions(+), 46 deletions(-) diff --git a/client/simulate_crash_mac_test.cc b/client/simulate_crash_mac_test.cc index 8334e95..faee615 100644 --- a/client/simulate_crash_mac_test.cc +++ b/client/simulate_crash_mac_test.cc @@ -89,6 +89,7 @@ class TestSimulateCrashMac final : public MachMultiprocess, mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer, bool* destroy_complex_request) override { *destroy_complex_request = true; diff --git a/snapshot/mac/mach_o_image_annotations_reader_test.cc b/snapshot/mac/mach_o_image_annotations_reader_test.cc index 194f685..60f97cc 100644 --- a/snapshot/mac/mach_o_image_annotations_reader_test.cc +++ b/snapshot/mac/mach_o_image_annotations_reader_test.cc @@ -81,6 +81,7 @@ class TestMachOImageAnnotationsReader final : public MachMultiprocess, mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer, bool* destroy_complex_request) override { *destroy_complex_request = true; diff --git a/tools/catch_exception_tool.cc b/tools/catch_exception_tool.cc index b18f9b5..3fcc221 100644 --- a/tools/catch_exception_tool.cc +++ b/tools/catch_exception_tool.cc @@ -70,6 +70,7 @@ class ExceptionServer : public UniversalMachExcServer { mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer, bool* destroy_complex_request) override { *destroy_complex_request = true; ++*exceptions_handled_; diff --git a/util/mach/child_port_handshake.cc b/util/mach/child_port_handshake.cc index c5344bb..483c102 100644 --- a/util/mach/child_port_handshake.cc +++ b/util/mach/child_port_handshake.cc @@ -247,6 +247,7 @@ kern_return_t ChildPortHandshake::HandleChildPortCheckIn( const child_port_token_t token, mach_port_t port, mach_msg_type_name_t right_type, + const mach_msg_trailer_t* trailer, bool* destroy_complex_request) { DCHECK_EQ(child_port_, kMachPortNull); diff --git a/util/mach/child_port_handshake.h b/util/mach/child_port_handshake.h index 3942e4b..f20acc8 100644 --- a/util/mach/child_port_handshake.h +++ b/util/mach/child_port_handshake.h @@ -136,6 +136,7 @@ class ChildPortHandshake : public ChildPortServer::Interface { child_port_token_t token, mach_port_t port, mach_msg_type_name_t right_type, + const mach_msg_trailer_t* trailer, bool* destroy_complex_request) override; //! \brief Runs the client. diff --git a/util/mach/child_port_server.cc b/util/mach/child_port_server.cc index b263b90..2118d03 100644 --- a/util/mach/child_port_server.cc +++ b/util/mach/child_port_server.cc @@ -72,6 +72,9 @@ bool ChildPortServer::MachMessageServerFunction( bool* destroy_complex_request) { PrepareMIGReplyFromRequest(in_header, out_header); + const mach_msg_trailer_t* in_trailer = + MachMessageTrailerFromHeader(in_header); + switch (in_header->msgh_id) { case kMachMessageIDChildPortCheckIn: { // child_port_check_in(), handle_child_port_check_in(). @@ -90,6 +93,7 @@ bool ChildPortServer::MachMessageServerFunction( in_request->token, in_request->port.name, in_request->port.disposition, + in_trailer, destroy_complex_request); return true; } diff --git a/util/mach/child_port_server.h b/util/mach/child_port_server.h index 4d4e7d8..8083a1e 100644 --- a/util/mach/child_port_server.h +++ b/util/mach/child_port_server.h @@ -35,6 +35,7 @@ class ChildPortServer : public MachMessageServer::Interface { //! This behaves equivalently to a `handle_child_port_check_in()` function //! used with `child_port_server()`. //! + //! \param[in] trailer The trailer received with the request message. //! \param[out] destroy_request `true` if the request message is to be //! destroyed even when this method returns success. See //! MachMessageServer::Interface. @@ -43,6 +44,7 @@ class ChildPortServer : public MachMessageServer::Interface { const child_port_token_t token, mach_port_t port, mach_msg_type_name_t right_type, + const mach_msg_trailer_t* trailer, bool* destroy_complex_request) = 0; protected: diff --git a/util/mach/child_port_server_test.cc b/util/mach/child_port_server_test.cc index ff9d83d..ddc525b 100644 --- a/util/mach/child_port_server_test.cc +++ b/util/mach/child_port_server_test.cc @@ -48,7 +48,7 @@ struct __attribute__((packed, aligned(4))) ChildPortCheckInRequest { memset(this, 0xa5, sizeof(*this)); Head.msgh_bits = MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND) | MACH_MSGH_BITS_COMPLEX; - Head.msgh_size = sizeof(*this); + Head.msgh_size = sizeof(*this) - sizeof(trailer); Head.msgh_remote_port = MACH_PORT_NULL; Head.msgh_local_port = kServerLocalPort; Head.msgh_id = 10011; @@ -65,6 +65,7 @@ struct __attribute__((packed, aligned(4))) ChildPortCheckInRequest { mach_msg_port_descriptor_t port; NDR_record_t NDR; child_port_token_t token; + mach_msg_trailer_t trailer; }; struct MIGReply : public mig_reply_error_t { @@ -87,11 +88,12 @@ struct MIGReply : public mig_reply_error_t { class MockChildPortServerInterface : public ChildPortServer::Interface { public: - MOCK_METHOD5(HandleChildPortCheckIn, + MOCK_METHOD6(HandleChildPortCheckIn, kern_return_t(child_port_server_t server, const child_port_token_t token, mach_port_t port, mach_msg_type_name_t right_type, + const mach_msg_trailer_t* trailer, bool* destroy_complex_request)); }; @@ -100,7 +102,7 @@ TEST(ChildPortServer, MockChildPortCheckIn) { ChildPortServer server(&server_interface); ChildPortCheckInRequest request; - EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize()); + EXPECT_LE(request.Head.msgh_size, server.MachMessageServerRequestSize()); MIGReply reply; EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize()); @@ -110,6 +112,7 @@ TEST(ChildPortServer, MockChildPortCheckIn) { kCheckInToken, kCheckInPort, kCheckInPortRightType, + Eq(&request.trailer), Pointee(Eq(false)))) .WillOnce(Return(MIG_NO_REPLY)) .RetiresOnSaturation(); diff --git a/util/mach/exc_client_variants_test.cc b/util/mach/exc_client_variants_test.cc index 1643a75..dd2036e 100644 --- a/util/mach/exc_client_variants_test.cc +++ b/util/mach/exc_client_variants_test.cc @@ -60,6 +60,7 @@ class TestExcClientVariants : public UniversalMachExcServer, mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer, bool* destroy_complex_request) override { *destroy_complex_request = true; diff --git a/util/mach/exc_server_variants.cc b/util/mach/exc_server_variants.cc index 4408eeb..34d7f96 100644 --- a/util/mach/exc_server_variants.cc +++ b/util/mach/exc_server_variants.cc @@ -196,6 +196,9 @@ bool ExcServer::MachMessageServerFunction(const mach_msg_header_t* in_header, bool* destroy_complex_request) { PrepareMIGReplyFromRequest(in_header, out_header); + const mach_msg_trailer_t* in_trailer = + MachMessageTrailerFromHeader(in_header); + switch (in_header->msgh_id) { case kMachMessageIDExceptionRaise: { // exception_raise(), catch_exception_raise(). @@ -216,6 +219,7 @@ bool ExcServer::MachMessageServerFunction(const mach_msg_header_t* in_header, in_request->exception, in_request->code, in_request->codeCnt, + in_trailer, destroy_complex_request); if (out_reply->RetCode != KERN_SUCCESS) { return true; @@ -253,7 +257,8 @@ bool ExcServer::MachMessageServerFunction(const mach_msg_header_t* in_header, in_request_1->old_state, in_request_1->old_stateCnt, out_reply->new_state, - &out_reply->new_stateCnt); + &out_reply->new_stateCnt, + in_trailer); if (out_reply->RetCode != KERN_SUCCESS) { return true; } @@ -296,6 +301,7 @@ bool ExcServer::MachMessageServerFunction(const mach_msg_header_t* in_header, in_request_1->old_stateCnt, out_reply->new_state, &out_reply->new_stateCnt, + in_trailer, destroy_complex_request); if (out_reply->RetCode != KERN_SUCCESS) { return true; @@ -331,6 +337,9 @@ bool MachExcServer::MachMessageServerFunction( bool* destroy_complex_request) { PrepareMIGReplyFromRequest(in_header, out_header); + const mach_msg_trailer_t* in_trailer = + MachMessageTrailerFromHeader(in_header); + switch (in_header->msgh_id) { case kMachMessageIDMachExceptionRaise: { // mach_exception_raise(), catch_mach_exception_raise(). @@ -351,6 +360,7 @@ bool MachExcServer::MachMessageServerFunction( in_request->exception, in_request->code, in_request->codeCnt, + in_trailer, destroy_complex_request); if (out_reply->RetCode != KERN_SUCCESS) { return true; @@ -388,7 +398,8 @@ bool MachExcServer::MachMessageServerFunction( in_request_1->old_state, in_request_1->old_stateCnt, out_reply->new_state, - &out_reply->new_stateCnt); + &out_reply->new_stateCnt, + in_trailer); if (out_reply->RetCode != KERN_SUCCESS) { return true; } @@ -431,6 +442,7 @@ bool MachExcServer::MachMessageServerFunction( in_request_1->old_stateCnt, out_reply->new_state, &out_reply->new_stateCnt, + in_trailer, destroy_complex_request); if (out_reply->RetCode != KERN_SUCCESS) { return true; @@ -469,6 +481,7 @@ kern_return_t SimplifiedExcServer::CatchExceptionRaise( exception_type_t exception, const exception_data_type_t* code, mach_msg_type_number_t code_count, + const mach_msg_trailer_t* trailer, bool* destroy_request) { thread_state_flavor_t flavor = THREAD_STATE_NONE; mach_msg_type_number_t new_state_count = 0; @@ -484,6 +497,7 @@ kern_return_t SimplifiedExcServer::CatchExceptionRaise( 0, nullptr, &new_state_count, + trailer, destroy_request); } @@ -496,7 +510,8 @@ kern_return_t SimplifiedExcServer::CatchExceptionRaiseState( const natural_t* old_state, mach_msg_type_number_t old_state_count, thread_state_t new_state, - mach_msg_type_number_t* new_state_count) { + mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer) { bool destroy_complex_request = false; return interface_->CatchException(EXCEPTION_STATE, exception_port, @@ -510,6 +525,7 @@ kern_return_t SimplifiedExcServer::CatchExceptionRaiseState( old_state_count, new_state, new_state_count, + trailer, &destroy_complex_request); } @@ -525,6 +541,7 @@ kern_return_t SimplifiedExcServer::CatchExceptionRaiseStateIdentity( mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer, bool* destroy_request) { return interface_->CatchException(EXCEPTION_STATE_IDENTITY, exception_port, @@ -538,6 +555,7 @@ kern_return_t SimplifiedExcServer::CatchExceptionRaiseStateIdentity( old_state_count, new_state, new_state_count, + trailer, destroy_request); } @@ -555,6 +573,7 @@ kern_return_t SimplifiedMachExcServer::CatchMachExceptionRaise( exception_type_t exception, const mach_exception_data_type_t* code, mach_msg_type_number_t code_count, + const mach_msg_trailer_t* trailer, bool* destroy_request) { thread_state_flavor_t flavor = THREAD_STATE_NONE; mach_msg_type_number_t new_state_count = 0; @@ -571,6 +590,7 @@ kern_return_t SimplifiedMachExcServer::CatchMachExceptionRaise( 0, nullptr, &new_state_count, + trailer, destroy_request); } @@ -583,7 +603,8 @@ kern_return_t SimplifiedMachExcServer::CatchMachExceptionRaiseState( const natural_t* old_state, mach_msg_type_number_t old_state_count, thread_state_t new_state, - mach_msg_type_number_t* new_state_count) { + mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer) { bool destroy_complex_request = false; return interface_->CatchMachException(EXCEPTION_STATE | MACH_EXCEPTION_CODES, exception_port, @@ -597,6 +618,7 @@ kern_return_t SimplifiedMachExcServer::CatchMachExceptionRaiseState( old_state_count, new_state, new_state_count, + trailer, &destroy_complex_request); } @@ -612,6 +634,7 @@ kern_return_t SimplifiedMachExcServer::CatchMachExceptionRaiseStateIdentity( mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer, bool* destroy_request) { return interface_->CatchMachException( EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, @@ -626,6 +649,7 @@ kern_return_t SimplifiedMachExcServer::CatchMachExceptionRaiseStateIdentity( old_state_count, new_state, new_state_count, + trailer, destroy_request); } @@ -686,6 +710,7 @@ kern_return_t UniversalMachExcServer::CatchException( mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer, bool* destroy_complex_request) { std::vector mach_codes; mach_codes.reserve(code_count); @@ -705,6 +730,7 @@ kern_return_t UniversalMachExcServer::CatchException( old_state_count, new_state, new_state_count, + trailer, destroy_complex_request); } diff --git a/util/mach/exc_server_variants.h b/util/mach/exc_server_variants.h index 75e81e4..96a95bf 100644 --- a/util/mach/exc_server_variants.h +++ b/util/mach/exc_server_variants.h @@ -42,6 +42,7 @@ class ExcServer : public MachMessageServer::Interface { //! This behaves equivalently to a `catch_exception_raise()` function used //! with `exc_server()`. //! + //! \param[in] trailer The trailer received with the request message. //! \param[out] destroy_request `true` if the request message is to be //! destroyed even when this method returns success. See //! MachMessageServer::Interface. @@ -52,6 +53,7 @@ class ExcServer : public MachMessageServer::Interface { exception_type_t exception, const exception_data_type_t* code, mach_msg_type_number_t code_count, + const mach_msg_trailer_t* trailer, bool* destroy_request) = 0; //! \brief Handles exceptions raised by `exception_raise_state()`. @@ -63,6 +65,8 @@ class ExcServer : public MachMessageServer::Interface { //! CatchExceptionRaise() and CatchExceptionRaiseStateIdentity(), the //! request message is not complex (it does not carry the \a thread or \a //! task port rights) and thus there is nothing to destroy. + //! + //! \param[in] trailer The trailer received with the request message. virtual kern_return_t CatchExceptionRaiseState( exception_handler_t exception_port, exception_type_t exception, @@ -72,13 +76,15 @@ class ExcServer : public MachMessageServer::Interface { const natural_t* old_state, mach_msg_type_number_t old_state_count, thread_state_t new_state, - mach_msg_type_number_t* new_state_count) = 0; + mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer) = 0; //! \brief Handles exceptions raised by `exception_raise_state_identity()`. //! //! This behaves equivalently to a `catch_exception_raise_state_identity()` //! function used with `exc_server()`. //! + //! \param[in] trailer The trailer received with the request message. //! \param[out] destroy_request `true` if the request message is to be //! destroyed even when this method returns success. See //! MachMessageServer::Interface. @@ -94,6 +100,7 @@ class ExcServer : public MachMessageServer::Interface { mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer, bool* destroy_request) = 0; protected: @@ -132,6 +139,7 @@ class MachExcServer : public MachMessageServer::Interface { //! This behaves equivalently to a `catch_mach_exception_raise()` function //! used with `mach_exc_server()`. //! + //! \param[in] trailer The trailer received with the request message. //! \param[out] destroy_request `true` if the request message is to be //! destroyed even when this method returns success. See //! MachMessageServer::Interface. @@ -142,6 +150,7 @@ class MachExcServer : public MachMessageServer::Interface { exception_type_t exception, const mach_exception_data_type_t* code, mach_msg_type_number_t code_count, + const mach_msg_trailer_t* trailer, bool* destroy_request) = 0; //! \brief Handles exceptions raised by `mach_exception_raise_state()`. @@ -153,6 +162,8 @@ class MachExcServer : public MachMessageServer::Interface { //! CatchMachExceptionRaise() and CatchMachExceptionRaiseStateIdentity(), //! the request message is not complex (it does not carry the \a thread or //! \a task port rights) and thus there is nothing to destroy. + //! + //! \param[in] trailer The trailer received with the request message. virtual kern_return_t CatchMachExceptionRaiseState( exception_handler_t exception_port, exception_type_t exception, @@ -162,7 +173,8 @@ class MachExcServer : public MachMessageServer::Interface { const natural_t* old_state, mach_msg_type_number_t old_state_count, thread_state_t new_state, - mach_msg_type_number_t* new_state_count) = 0; + mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer) = 0; //! \brief Handles exceptions raised by //! `mach_exception_raise_state_identity()`. @@ -171,6 +183,7 @@ class MachExcServer : public MachMessageServer::Interface { //! `catch_mach_exception_raise_state_identity()` function used with //! `mach_exc_server()`. //! + //! \param[in] trailer The trailer received with the request message. //! \param[out] destroy_request `true` if the request message is to be //! destroyed even when this method returns success. See //! MachMessageServer::Interface. @@ -186,6 +199,7 @@ class MachExcServer : public MachMessageServer::Interface { mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer, bool* destroy_request) = 0; protected: @@ -248,6 +262,7 @@ class SimplifiedExcServer : public ExcServer, public ExcServer::Interface { mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer, bool* destroy_complex_request) = 0; protected: @@ -267,6 +282,7 @@ class SimplifiedExcServer : public ExcServer, public ExcServer::Interface { exception_type_t exception, const exception_data_type_t* code, mach_msg_type_number_t code_count, + const mach_msg_trailer_t* trailer, bool* destroy_request) override; kern_return_t CatchExceptionRaiseState( exception_handler_t exception_port, @@ -277,7 +293,8 @@ class SimplifiedExcServer : public ExcServer, public ExcServer::Interface { const natural_t* old_state, mach_msg_type_number_t old_state_count, thread_state_t new_state, - mach_msg_type_number_t* new_state_count) override; + mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer) override; kern_return_t CatchExceptionRaiseStateIdentity( exception_handler_t exception_port, thread_t thread, @@ -290,6 +307,7 @@ class SimplifiedExcServer : public ExcServer, public ExcServer::Interface { mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer, bool* destroy_request) override; private: @@ -344,6 +362,7 @@ class SimplifiedMachExcServer : public MachExcServer, mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer, bool* destroy_complex_request) = 0; protected: @@ -363,6 +382,7 @@ class SimplifiedMachExcServer : public MachExcServer, exception_type_t exception, const mach_exception_data_type_t* code, mach_msg_type_number_t code_count, + const mach_msg_trailer_t* trailer, bool* destroy_request) override; kern_return_t CatchMachExceptionRaiseState( exception_handler_t exception_port, @@ -373,7 +393,8 @@ class SimplifiedMachExcServer : public MachExcServer, const natural_t* old_state, mach_msg_type_number_t old_state_count, thread_state_t new_state, - mach_msg_type_number_t* new_state_count) override; + mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer) override; kern_return_t CatchMachExceptionRaiseStateIdentity( exception_handler_t exception_port, thread_t thread, @@ -386,6 +407,7 @@ class SimplifiedMachExcServer : public MachExcServer, mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer, bool* destroy_request) override; private: @@ -440,6 +462,7 @@ class UniversalMachExcServer mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer, bool* destroy_complex_request) override; private: diff --git a/util/mach/exc_server_variants_test.cc b/util/mach/exc_server_variants_test.cc index 4c9a796..8cf34d4 100644 --- a/util/mach/exc_server_variants_test.cc +++ b/util/mach/exc_server_variants_test.cc @@ -23,6 +23,7 @@ #include "gtest/gtest.h" #include "util/mach/exception_behaviors.h" #include "util/mach/mach_extensions.h" +#include "util/mach/mach_message_util.h" #include "util/test/mac/mach_errors.h" #include "util/test/mac/mach_multiprocess.h" @@ -82,7 +83,7 @@ struct __attribute__((packed, aligned(4))) ExceptionRaiseRequest { Head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, MACH_MSG_TYPE_PORT_SEND) | MACH_MSGH_BITS_COMPLEX; - Head.msgh_size = sizeof(*this); + Head.msgh_size = sizeof(*this) - sizeof(trailer); Head.msgh_remote_port = kClientRemotePort; Head.msgh_local_port = kServerLocalPort; Head.msgh_id = 2401; @@ -104,6 +105,7 @@ struct __attribute__((packed, aligned(4))) ExceptionRaiseRequest { exception_type_t exception; mach_msg_type_number_t codeCnt; integer_t code[2]; + mach_msg_trailer_t trailer; }; struct __attribute__((packed, aligned(4))) ExceptionRaiseReply { @@ -149,7 +151,7 @@ struct __attribute__((packed, aligned(4))) ExceptionRaiseStateRequest { memset(this, 0xa5, sizeof(*this)); Head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, MACH_MSG_TYPE_PORT_SEND); - Head.msgh_size = sizeof(*this); + Head.msgh_size = sizeof(*this) - sizeof(trailer); Head.msgh_remote_port = kClientRemotePort; Head.msgh_local_port = kServerLocalPort; Head.msgh_id = 2402; @@ -166,6 +168,12 @@ struct __attribute__((packed, aligned(4))) ExceptionRaiseStateRequest { Head.msgh_size += sizeof(old_state[0]) * old_stateCnt - sizeof(old_state); } + // Because the message size has been adjusted, the trailer may not appear in + // its home member variable. This computes the actual address of the trailer. + const mach_msg_trailer_t* Trailer() const { + return MachMessageTrailerFromHeader(&Head); + } + mach_msg_header_t Head; NDR_record_t NDR; exception_type_t exception; @@ -174,6 +182,7 @@ struct __attribute__((packed, aligned(4))) ExceptionRaiseStateRequest { int flavor; mach_msg_type_number_t old_stateCnt; natural_t old_state[THREAD_STATE_MAX]; + mach_msg_trailer_t trailer; }; struct __attribute__((packed, aligned(4))) ExceptionRaiseStateReply { @@ -232,7 +241,7 @@ struct __attribute__((packed, aligned(4))) ExceptionRaiseStateIdentityRequest { Head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, MACH_MSG_TYPE_PORT_SEND) | MACH_MSGH_BITS_COMPLEX; - Head.msgh_size = sizeof(*this); + Head.msgh_size = sizeof(*this) - sizeof(trailer); Head.msgh_remote_port = kClientRemotePort; Head.msgh_local_port = kServerLocalPort; Head.msgh_id = 2403; @@ -252,6 +261,12 @@ struct __attribute__((packed, aligned(4))) ExceptionRaiseStateIdentityRequest { Head.msgh_size += sizeof(old_state[0]) * old_stateCnt - sizeof(old_state); } + // Because the message size has been adjusted, the trailer may not appear in + // its home member variable. This computes the actual address of the trailer. + const mach_msg_trailer_t* Trailer() const { + return MachMessageTrailerFromHeader(&Head); + } + mach_msg_header_t Head; mach_msg_body_t msgh_body; mach_msg_port_descriptor_t thread; @@ -263,6 +278,7 @@ struct __attribute__((packed, aligned(4))) ExceptionRaiseStateIdentityRequest { int flavor; mach_msg_type_number_t old_stateCnt; natural_t old_state[THREAD_STATE_MAX]; + mach_msg_trailer_t trailer; }; // The reply messages for exception_raise_state and @@ -275,7 +291,7 @@ struct __attribute__((packed, aligned(4))) MachExceptionRaiseRequest { Head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, MACH_MSG_TYPE_PORT_SEND) | MACH_MSGH_BITS_COMPLEX; - Head.msgh_size = sizeof(*this); + Head.msgh_size = sizeof(*this) - sizeof(trailer); Head.msgh_remote_port = kClientRemotePort; Head.msgh_local_port = kServerLocalPort; Head.msgh_id = 2405; @@ -297,6 +313,7 @@ struct __attribute__((packed, aligned(4))) MachExceptionRaiseRequest { exception_type_t exception; mach_msg_type_number_t codeCnt; int64_t code[2]; + mach_msg_trailer_t trailer; }; // The reply messages for exception_raise and mach_exception_raise are @@ -308,7 +325,7 @@ struct __attribute__((packed, aligned(4))) MachExceptionRaiseStateRequest { memset(this, 0xa5, sizeof(*this)); Head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, MACH_MSG_TYPE_PORT_SEND); - Head.msgh_size = sizeof(*this); + Head.msgh_size = sizeof(*this) - sizeof(trailer); Head.msgh_remote_port = kClientRemotePort; Head.msgh_local_port = kServerLocalPort; Head.msgh_id = 2406; @@ -325,6 +342,12 @@ struct __attribute__((packed, aligned(4))) MachExceptionRaiseStateRequest { Head.msgh_size += sizeof(old_state[0]) * old_stateCnt - sizeof(old_state); } + // Because the message size has been adjusted, the trailer may not appear in + // its home member variable. This computes the actual address of the trailer. + const mach_msg_trailer_t* Trailer() const { + return MachMessageTrailerFromHeader(&Head); + } + mach_msg_header_t Head; NDR_record_t NDR; exception_type_t exception; @@ -333,6 +356,7 @@ struct __attribute__((packed, aligned(4))) MachExceptionRaiseStateRequest { int flavor; mach_msg_type_number_t old_stateCnt; natural_t old_state[THREAD_STATE_MAX]; + mach_msg_trailer_t trailer; }; // The reply messages for exception_raise_state and mach_exception_raise_state @@ -346,7 +370,7 @@ struct __attribute__((packed, Head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, MACH_MSG_TYPE_PORT_SEND) | MACH_MSGH_BITS_COMPLEX; - Head.msgh_size = sizeof(*this); + Head.msgh_size = sizeof(*this) - sizeof(trailer); Head.msgh_remote_port = kClientRemotePort; Head.msgh_local_port = kServerLocalPort; Head.msgh_id = 2407; @@ -366,6 +390,12 @@ struct __attribute__((packed, Head.msgh_size += sizeof(old_state[0]) * old_stateCnt - sizeof(old_state); } + // Because the message size has been adjusted, the trailer may not appear in + // its home member variable. This computes the actual address of the trailer. + const mach_msg_trailer_t* Trailer() const { + return MachMessageTrailerFromHeader(&Head); + } + mach_msg_header_t Head; mach_msg_body_t msgh_body; mach_msg_port_descriptor_t thread; @@ -377,6 +407,7 @@ struct __attribute__((packed, int flavor; mach_msg_type_number_t old_stateCnt; natural_t old_state[THREAD_STATE_MAX]; + mach_msg_trailer_t trailer; }; // The reply messages for exception_raise_state_identity and @@ -449,6 +480,7 @@ class MockUniversalMachExcServer : public UniversalMachExcServer { mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer, bool* destroy_complex_request) override { *destroy_complex_request = true; const ConstExceptionCodes exception_codes = {code, code_count}; @@ -462,19 +494,21 @@ class MockUniversalMachExcServer : public UniversalMachExcServer { &exception_codes, flavor, &old_thread_state, - &new_thread_state); + &new_thread_state, + trailer); } - MOCK_METHOD9(MockCatchMachException, - kern_return_t(exception_behavior_t behavior, - exception_handler_t exception_port, - thread_t thread, - task_t task, - exception_type_t exception, - const ConstExceptionCodes* exception_codes, - thread_state_flavor_t* flavor, - const ConstThreadState* old_thread_state, - ThreadState* new_thread_state)); + MOCK_METHOD10(MockCatchMachException, + kern_return_t(exception_behavior_t behavior, + exception_handler_t exception_port, + thread_t thread, + task_t task, + exception_type_t exception, + const ConstExceptionCodes* exception_codes, + thread_state_flavor_t* flavor, + const ConstThreadState* old_thread_state, + ThreadState* new_thread_state, + const mach_msg_trailer_t* trailer)); }; // Matcher for ConstExceptionCodes, testing that it carries 2 codes matching @@ -548,7 +582,7 @@ TEST(ExcServerVariants, MockExceptionRaise) { MockUniversalMachExcServer server; ExceptionRaiseRequest request; - EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize()); + EXPECT_LE(request.Head.msgh_size, server.MachMessageServerRequestSize()); ExceptionRaiseReply reply; EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize()); @@ -565,7 +599,8 @@ TEST(ExcServerVariants, MockExceptionRaise) { kTestExceptonCodes[1]), Pointee(Eq(THREAD_STATE_NONE)), IsThreadStateCount(0u), - IsThreadStateCount(0u))) + IsThreadStateCount(0u), + Eq(&request.trailer))) .WillOnce(Return(KERN_SUCCESS)) .RetiresOnSaturation(); @@ -585,7 +620,7 @@ TEST(ExcServerVariants, MockExceptionRaiseState) { MockUniversalMachExcServer server; ExceptionRaiseStateRequest request; - EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize()); + EXPECT_LE(request.Head.msgh_size, server.MachMessageServerRequestSize()); ExceptionRaiseStateReply reply; EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize()); @@ -603,7 +638,8 @@ TEST(ExcServerVariants, MockExceptionRaiseState) { AreExceptionCodes(kTestExceptonCodes[0], kTestExceptonCodes[1]), Pointee(Eq(kThreadStateFlavor)), IsThreadStateCount(kThreadStateFlavorCount), - IsThreadStateCount(arraysize(reply.new_state)))) + IsThreadStateCount(arraysize(reply.new_state)), + Eq(request.Trailer()))) .WillOnce(Return(KERN_SUCCESS)) .RetiresOnSaturation(); @@ -626,7 +662,7 @@ TEST(ExcServerVariants, MockExceptionRaiseStateIdentity) { MockUniversalMachExcServer server; ExceptionRaiseStateIdentityRequest request; - EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize()); + EXPECT_LE(request.Head.msgh_size, server.MachMessageServerRequestSize()); ExceptionRaiseStateIdentityReply reply; EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize()); @@ -644,7 +680,8 @@ TEST(ExcServerVariants, MockExceptionRaiseStateIdentity) { AreExceptionCodes(kTestExceptonCodes[0], kTestExceptonCodes[1]), Pointee(Eq(kThreadStateFlavor)), IsThreadStateCount(kThreadStateFlavorCount), - IsThreadStateCount(arraysize(reply.new_state)))) + IsThreadStateCount(arraysize(reply.new_state)), + Eq(request.Trailer()))) .WillOnce(Return(KERN_SUCCESS)) .RetiresOnSaturation(); @@ -664,7 +701,7 @@ TEST(ExcServerVariants, MockMachExceptionRaise) { MockUniversalMachExcServer server; MachExceptionRaiseRequest request; - EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize()); + EXPECT_LE(request.Head.msgh_size, server.MachMessageServerRequestSize()); MachExceptionRaiseReply reply; EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize()); @@ -683,7 +720,8 @@ TEST(ExcServerVariants, MockMachExceptionRaise) { kTestMachExceptionCodes[1]), Pointee(Eq(THREAD_STATE_NONE)), IsThreadStateCount(0u), - IsThreadStateCount(0u))) + IsThreadStateCount(0u), + Eq(&request.trailer))) .WillOnce(Return(KERN_SUCCESS)) .RetiresOnSaturation(); @@ -703,7 +741,7 @@ TEST(ExcServerVariants, MockMachExceptionRaiseState) { MockUniversalMachExcServer server; MachExceptionRaiseStateRequest request; - EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize()); + EXPECT_LE(request.Head.msgh_size, server.MachMessageServerRequestSize()); MachExceptionRaiseStateReply reply; EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize()); @@ -722,7 +760,8 @@ TEST(ExcServerVariants, MockMachExceptionRaiseState) { kTestMachExceptionCodes[1]), Pointee(Eq(kThreadStateFlavor)), IsThreadStateCount(kThreadStateFlavorCount), - IsThreadStateCount(arraysize(reply.new_state)))) + IsThreadStateCount(arraysize(reply.new_state)), + Eq(request.Trailer()))) .WillOnce(Return(KERN_SUCCESS)) .RetiresOnSaturation(); @@ -745,7 +784,7 @@ TEST(ExcServerVariants, MockMachExceptionRaiseStateIdentity) { MockUniversalMachExcServer server; MachExceptionRaiseStateIdentityRequest request; - EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize()); + EXPECT_LE(request.Head.msgh_size, server.MachMessageServerRequestSize()); MachExceptionRaiseStateIdentityReply reply; EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize()); @@ -764,7 +803,8 @@ TEST(ExcServerVariants, MockMachExceptionRaiseStateIdentity) { kTestMachExceptionCodes[1]), Pointee(Eq(kThreadStateFlavor)), IsThreadStateCount(kThreadStateFlavorCount), - IsThreadStateCount(arraysize(reply.new_state)))) + IsThreadStateCount(arraysize(reply.new_state)), + Eq(request.Trailer()))) .WillOnce(Return(KERN_SUCCESS)) .RetiresOnSaturation(); @@ -871,6 +911,7 @@ class TestExcServerVariants : public UniversalMachExcServer, mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer, bool* destroy_complex_request) override { *destroy_complex_request = true; @@ -917,6 +958,11 @@ class TestExcServerVariants : public UniversalMachExcServer, EXPECT_EQ(nullptr, new_state); } + EXPECT_EQ(implicit_cast(MACH_MSG_TRAILER_FORMAT_0), + trailer->msgh_trailer_type); + EXPECT_EQ(REQUESTED_TRAILER_SIZE(kMachMessageOptions), + trailer->msgh_trailer_size); + return ExcServerSuccessfulReturnValue(behavior, false); } @@ -927,7 +973,7 @@ class TestExcServerVariants : public UniversalMachExcServer, kern_return_t kr = MachMessageServer::Run(this, LocalPort(), - MACH_MSG_OPTION_NONE, + kMachMessageOptions, MachMessageServer::kOneShot, MachMessageServer::kBlocking, MachMessageServer::kReceiveLargeError, @@ -954,6 +1000,9 @@ class TestExcServerVariants : public UniversalMachExcServer, mach_msg_type_number_t state_count_; bool handled_; + static const mach_msg_option_t kMachMessageOptions = + MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0); + DISALLOW_COPY_AND_ASSIGN(TestExcServerVariants); }; diff --git a/util/mach/exception_ports_test.cc b/util/mach/exception_ports_test.cc index 6e5253c..24b1648 100644 --- a/util/mach/exception_ports_test.cc +++ b/util/mach/exception_ports_test.cc @@ -154,6 +154,7 @@ class TestExceptionPorts : public UniversalMachExcServer, mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer, bool* destroy_complex_request) override { *destroy_complex_request = true; diff --git a/util/mach/mach_message_server.cc b/util/mach/mach_message_server.cc index c0f848d..08760fc 100644 --- a/util/mach/mach_message_server.cc +++ b/util/mach/mach_message_server.cc @@ -111,7 +111,8 @@ mach_msg_return_t MachMessageServer::Run(Interface* interface, mach_msg_size_t trailer_alloc = REQUESTED_TRAILER_SIZE(options); mach_msg_size_t max_request_size = interface->MachMessageServerRequestSize(); - mach_msg_size_t request_alloc = round_page(max_request_size + trailer_alloc); + mach_msg_size_t request_alloc = + round_page(round_msg(max_request_size) + trailer_alloc); // mach_msg_server() and mach_msg_server_once() invert this condition, but // their interpretation is incorrect. When it is desirable to retry a receive @@ -120,9 +121,10 @@ mach_msg_return_t MachMessageServer::Run(Interface* interface, // the initial receive attempt. On the other hand, when this behavior is not // requested, there is no reason to attempt receiving messages any larger than // expected. - mach_msg_size_t request_size = (receive_large == kReceiveLargeResize) - ? max_request_size + trailer_alloc - : request_alloc; + mach_msg_size_t request_size = + (receive_large == kReceiveLargeResize) + ? round_msg(max_request_size) + trailer_alloc + : request_alloc; mach_msg_size_t max_reply_size = interface->MachMessageServerReplySize(); @@ -186,7 +188,7 @@ mach_msg_return_t MachMessageServer::Run(Interface* interface, } else if (kr == MACH_RCV_TOO_LARGE && receive_large == kReceiveLargeResize) { this_request_size = - round_page(request_header->msgh_size + trailer_alloc); + round_page(round_msg(request_header->msgh_size) + trailer_alloc); this_request_alloc = this_request_size; } else { return kr; diff --git a/util/mach/mach_message_util.cc b/util/mach/mach_message_util.cc index a1392fe..a6e61d1 100644 --- a/util/mach/mach_message_util.cc +++ b/util/mach/mach_message_util.cc @@ -34,4 +34,11 @@ void SetMIGReplyError(mach_msg_header_t* out_header, kern_return_t error) { reinterpret_cast(out_header)->RetCode = error; } +const mach_msg_trailer_t* MachMessageTrailerFromHeader( + const mach_msg_header_t* header) { + vm_address_t header_address = reinterpret_cast(header); + vm_address_t trailer_address = header_address + round_msg(header->msgh_size); + return reinterpret_cast(trailer_address); +} + } // namespace crashpad diff --git a/util/mach/mach_message_util.h b/util/mach/mach_message_util.h index afe5981..dd5bc01 100644 --- a/util/mach/mach_message_util.h +++ b/util/mach/mach_message_util.h @@ -48,6 +48,20 @@ void PrepareMIGReplyFromRequest(const mach_msg_header_t* in_header, //! \sa PrepareMIGReplyFromRequest() void SetMIGReplyError(mach_msg_header_t* out_header, kern_return_t error); +//! \brief Returns a Mach message trailer for a message that has been received. +//! +//! This function must only be called on Mach messages that have been received +//! via the Mach messaging interface, such as `mach_msg()`. Messages constructed +//! for sending do not contain trailers. +//! +//! \param[in] header A pointer to a received Mach message. +//! +//! \return A pointer to the trailer following the received Mach message’s body. +//! The contents of the trailer depend on the options provided to +//! `mach_msg()` or a similar function when the message was received. +const mach_msg_trailer_t* MachMessageTrailerFromHeader( + const mach_msg_header_t* header); + } // namespace crashpad #endif // CRASHPAD_UTIL_MACH_MACH_MESSAGE_UTIL_H_ diff --git a/util/mach/mach_message_util_test.cc b/util/mach/mach_message_util_test.cc index b8ecbbd..6654306 100644 --- a/util/mach/mach_message_util_test.cc +++ b/util/mach/mach_message_util_test.cc @@ -63,6 +63,29 @@ TEST(MachMessageUtil, PrepareMIGReplyFromRequest_SetMIGReplyError) { EXPECT_EQ(MIG_BAD_ID, reply.RetCode); } +TEST(MachMessageUtil, MachMessageTrailerFromHeader) { + mach_msg_empty_t empty; + empty.send.header.msgh_size = sizeof(mach_msg_empty_send_t); + EXPECT_EQ(&empty.rcv.trailer, + MachMessageTrailerFromHeader(&empty.rcv.header)); + + struct TestSendMessage : public mach_msg_header_t { + uint8_t data[126]; + }; + struct TestReceiveMessage : public TestSendMessage { + mach_msg_trailer_t trailer; + }; + union TestMessage { + TestSendMessage send; + TestReceiveMessage receive; + }; + + TestMessage test; + test.send.msgh_size = sizeof(TestSendMessage); + EXPECT_EQ(&test.receive.trailer, + MachMessageTrailerFromHeader(&test.receive)); +} + } // namespace } // namespace test } // namespace crashpad