| Index: util/test/mac/mach_multiprocess.cc
|
| diff --git a/util/test/mac/mach_multiprocess.cc b/util/test/mac/mach_multiprocess.cc
|
| deleted file mode 100644
|
| index c558eb0565405d344c27c9a5211f2fca16b5d4dd..0000000000000000000000000000000000000000
|
| --- a/util/test/mac/mach_multiprocess.cc
|
| +++ /dev/null
|
| @@ -1,280 +0,0 @@
|
| -// Copyright 2014 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/test/mac/mach_multiprocess.h"
|
| -
|
| -#include <AvailabilityMacros.h>
|
| -#include <bsm/libbsm.h>
|
| -#include <servers/bootstrap.h>
|
| -
|
| -#include <string>
|
| -
|
| -#include "base/auto_reset.h"
|
| -#include "base/logging.h"
|
| -#include "base/mac/scoped_mach_port.h"
|
| -#include "base/memory/scoped_ptr.h"
|
| -#include "base/rand_util.h"
|
| -#include "gtest/gtest.h"
|
| -#include "util/file/file_io.h"
|
| -#include "util/mach/mach_extensions.h"
|
| -#include "util/mach/mach_message.h"
|
| -#include "util/misc/scoped_forbid_return.h"
|
| -#include "util/test/errors.h"
|
| -#include "util/test/mac/mach_errors.h"
|
| -
|
| -namespace {
|
| -
|
| -// The “hello” message contains a send right to the child process’ task port.
|
| -struct SendHelloMessage : public mach_msg_base_t {
|
| - mach_msg_port_descriptor_t port_descriptor;
|
| -};
|
| -
|
| -struct ReceiveHelloMessage : public SendHelloMessage {
|
| - union {
|
| - mach_msg_trailer_t trailer;
|
| - mach_msg_audit_trailer_t audit_trailer;
|
| - };
|
| -};
|
| -
|
| -} // namespace
|
| -
|
| -namespace crashpad {
|
| -namespace test {
|
| -
|
| -namespace internal {
|
| -
|
| -struct MachMultiprocessInfo {
|
| - MachMultiprocessInfo()
|
| - : service_name(),
|
| - local_port(MACH_PORT_NULL),
|
| - remote_port(MACH_PORT_NULL),
|
| - child_task(TASK_NULL) {
|
| - }
|
| -
|
| - std::string service_name;
|
| - base::mac::ScopedMachReceiveRight local_port;
|
| - base::mac::ScopedMachSendRight remote_port;
|
| - base::mac::ScopedMachSendRight child_task; // valid only in parent
|
| -};
|
| -
|
| -} // namespace internal
|
| -
|
| -MachMultiprocess::MachMultiprocess() : Multiprocess(), info_(nullptr) {
|
| -}
|
| -
|
| -void MachMultiprocess::Run() {
|
| - ASSERT_EQ(nullptr, info_);
|
| - scoped_ptr<internal::MachMultiprocessInfo> info(
|
| - new internal::MachMultiprocessInfo);
|
| - base::AutoReset<internal::MachMultiprocessInfo*> reset_info(&info_,
|
| - info.get());
|
| -
|
| - return Multiprocess::Run();
|
| -}
|
| -
|
| -MachMultiprocess::~MachMultiprocess() {
|
| -}
|
| -
|
| -void MachMultiprocess::PreFork() {
|
| - ASSERT_NO_FATAL_FAILURE(Multiprocess::PreFork());
|
| -
|
| - // Set up the parent port and register it with the bootstrap server before
|
| - // forking, so that it’s guaranteed to be there when the child attempts to
|
| - // look it up.
|
| - info_->service_name = "com.googlecode.crashpad.test.mach_multiprocess.";
|
| - for (int index = 0; index < 16; ++index) {
|
| - info_->service_name.append(1, base::RandInt('A', 'Z'));
|
| - }
|
| -
|
| - mach_port_t local_port;
|
| - kern_return_t kr = bootstrap_check_in(bootstrap_port,
|
| - info_->service_name.c_str(),
|
| - &local_port);
|
| - ASSERT_EQ(BOOTSTRAP_SUCCESS, kr)
|
| - << BootstrapErrorMessage(kr, "bootstrap_check_in");
|
| - info_->local_port.reset(local_port);
|
| -}
|
| -
|
| -mach_port_t MachMultiprocess::LocalPort() const {
|
| - EXPECT_NE(kMachPortNull, info_->local_port);
|
| - return info_->local_port;
|
| -}
|
| -
|
| -mach_port_t MachMultiprocess::RemotePort() const {
|
| - EXPECT_NE(kMachPortNull, info_->remote_port);
|
| - return info_->remote_port;
|
| -}
|
| -
|
| -task_t MachMultiprocess::ChildTask() const {
|
| - EXPECT_NE(TASK_NULL, info_->child_task);
|
| - return info_->child_task;
|
| -}
|
| -
|
| -void MachMultiprocess::MultiprocessParent() {
|
| - ReceiveHelloMessage message = {};
|
| -
|
| - kern_return_t kr = mach_msg(&message.header,
|
| - MACH_RCV_MSG | kMachMessageReceiveAuditTrailer,
|
| - 0,
|
| - sizeof(message),
|
| - info_->local_port,
|
| - MACH_MSG_TIMEOUT_NONE,
|
| - MACH_PORT_NULL);
|
| - ASSERT_EQ(MACH_MSG_SUCCESS, kr) << MachErrorMessage(kr, "mach_msg");
|
| -
|
| - // Comb through the entire message, checking every field against its expected
|
| - // value.
|
| - EXPECT_EQ(MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND, MACH_MSG_TYPE_MOVE_SEND) |
|
| - MACH_MSGH_BITS_COMPLEX,
|
| - message.header.msgh_bits);
|
| - ASSERT_EQ(sizeof(SendHelloMessage), message.header.msgh_size);
|
| - EXPECT_EQ(info_->local_port, message.header.msgh_local_port);
|
| - ASSERT_EQ(1u, message.body.msgh_descriptor_count);
|
| - EXPECT_EQ(implicit_cast<mach_msg_type_name_t>(MACH_MSG_TYPE_MOVE_SEND),
|
| - message.port_descriptor.disposition);
|
| - ASSERT_EQ(implicit_cast<mach_msg_descriptor_type_t>(MACH_MSG_PORT_DESCRIPTOR),
|
| - message.port_descriptor.type);
|
| - ASSERT_EQ(implicit_cast<mach_msg_trailer_type_t>(MACH_MSG_TRAILER_FORMAT_0),
|
| - message.audit_trailer.msgh_trailer_type);
|
| - ASSERT_EQ(sizeof(message.audit_trailer),
|
| - message.audit_trailer.msgh_trailer_size);
|
| - EXPECT_EQ(0u, message.audit_trailer.msgh_seqno);
|
| -
|
| - // Check the audit trailer’s values for sanity. This is a little bit of
|
| - // overkill, but because the service was registered with the bootstrap server
|
| - // and other processes will be able to look it up and send messages to it,
|
| - // these checks disambiguate genuine failures later on in the test from those
|
| - // that would occur if an errant process sends a message to this service.
|
| -#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8
|
| - uid_t audit_auid;
|
| - uid_t audit_euid;
|
| - gid_t audit_egid;
|
| - uid_t audit_ruid;
|
| - gid_t audit_rgid;
|
| - pid_t audit_pid;
|
| - au_asid_t audit_asid;
|
| - audit_token_to_au32(message.audit_trailer.msgh_audit,
|
| - &audit_auid,
|
| - &audit_euid,
|
| - &audit_egid,
|
| - &audit_ruid,
|
| - &audit_rgid,
|
| - &audit_pid,
|
| - &audit_asid,
|
| - nullptr);
|
| -#else
|
| - uid_t audit_auid = audit_token_to_auid(message.audit_trailer.msgh_audit);
|
| - uid_t audit_euid = audit_token_to_euid(message.audit_trailer.msgh_audit);
|
| - gid_t audit_egid = audit_token_to_egid(message.audit_trailer.msgh_audit);
|
| - uid_t audit_ruid = audit_token_to_ruid(message.audit_trailer.msgh_audit);
|
| - gid_t audit_rgid = audit_token_to_rgid(message.audit_trailer.msgh_audit);
|
| - pid_t audit_pid = audit_token_to_pid(message.audit_trailer.msgh_audit);
|
| - au_asid_t audit_asid = audit_token_to_asid(message.audit_trailer.msgh_audit);
|
| -#endif
|
| - EXPECT_EQ(geteuid(), audit_euid);
|
| - EXPECT_EQ(getegid(), audit_egid);
|
| - EXPECT_EQ(getuid(), audit_ruid);
|
| - EXPECT_EQ(getgid(), audit_rgid);
|
| - ASSERT_EQ(ChildPID(), audit_pid);
|
| -
|
| - ASSERT_EQ(ChildPID(), AuditPIDFromMachMessageTrailer(&message.trailer));
|
| -
|
| - auditinfo_addr_t audit_info;
|
| - int rv = getaudit_addr(&audit_info, sizeof(audit_info));
|
| - ASSERT_EQ(0, rv) << ErrnoMessage("getaudit_addr");
|
| - EXPECT_EQ(audit_info.ai_auid, audit_auid);
|
| - EXPECT_EQ(audit_info.ai_asid, audit_asid);
|
| -
|
| - // Retrieve the remote port from the message header, and the child’s task port
|
| - // from the message body.
|
| - info_->remote_port.reset(message.header.msgh_remote_port);
|
| - info_->child_task.reset(message.port_descriptor.name);
|
| -
|
| - // Verify that the child’s task port is what it purports to be.
|
| - int mach_pid;
|
| - kr = pid_for_task(info_->child_task, &mach_pid);
|
| - ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "pid_for_task");
|
| - ASSERT_EQ(ChildPID(), mach_pid);
|
| -
|
| - MachMultiprocessParent();
|
| -
|
| - info_->remote_port.reset();
|
| - info_->local_port.reset();
|
| -}
|
| -
|
| -void MachMultiprocess::MultiprocessChild() {
|
| - ScopedForbidReturn forbid_return;;
|
| -
|
| - // local_port is not valid in the forked child process.
|
| - ignore_result(info_->local_port.release());
|
| -
|
| - info_->local_port.reset(NewMachPort(MACH_PORT_RIGHT_RECEIVE));
|
| - ASSERT_NE(kMachPortNull, info_->local_port);
|
| -
|
| - // The remote port can be obtained from the bootstrap server.
|
| - mach_port_t remote_port;
|
| - kern_return_t kr = bootstrap_look_up(
|
| - bootstrap_port, info_->service_name.c_str(), &remote_port);
|
| - ASSERT_EQ(BOOTSTRAP_SUCCESS, kr)
|
| - << BootstrapErrorMessage(kr, "bootstrap_look_up");
|
| - info_->remote_port.reset(remote_port);
|
| -
|
| - // The “hello” message will provide the parent with its remote port, a send
|
| - // right to the child task’s local port receive right. It will also carry a
|
| - // send right to the child task’s task port.
|
| - SendHelloMessage message = {};
|
| - message.header.msgh_bits =
|
| - MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND) |
|
| - MACH_MSGH_BITS_COMPLEX;
|
| - message.header.msgh_size = sizeof(message);
|
| - message.header.msgh_remote_port = info_->remote_port;
|
| - message.header.msgh_local_port = info_->local_port;
|
| - message.body.msgh_descriptor_count = 1;
|
| - message.port_descriptor.name = mach_task_self();
|
| - message.port_descriptor.disposition = MACH_MSG_TYPE_COPY_SEND;
|
| - message.port_descriptor.type = MACH_MSG_PORT_DESCRIPTOR;
|
| -
|
| - kr = mach_msg(&message.header,
|
| - MACH_SEND_MSG,
|
| - message.header.msgh_size,
|
| - 0,
|
| - MACH_PORT_NULL,
|
| - MACH_MSG_TIMEOUT_NONE,
|
| - MACH_PORT_NULL);
|
| - ASSERT_EQ(MACH_MSG_SUCCESS, kr) << MachErrorMessage(kr, "mach_msg");
|
| -
|
| - MachMultiprocessChild();
|
| -
|
| - info_->remote_port.reset();
|
| - info_->local_port.reset();
|
| -
|
| - // Close the write pipe now, for cases where the parent is waiting on it to
|
| - // be closed as an indication that the child has finished.
|
| - CloseWritePipe();
|
| -
|
| - // Wait for the parent process to close its end of the pipe. The child process
|
| - // needs to remain alive until then because the parent process will attempt to
|
| - // verify it using the task port it has access to via ChildTask().
|
| - CheckedReadFileAtEOF(ReadPipeHandle());
|
| -
|
| - if (testing::Test::HasFailure()) {
|
| - // Trigger the ScopedForbidReturn destructor.
|
| - return;
|
| - }
|
| -
|
| - forbid_return.Disarm();
|
| -}
|
| -
|
| -} // namespace test
|
| -} // namespace crashpad
|
|
|