// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
#ifdef XP_MACOSX # include <bsm/libbsm.h> # include <servers/bootstrap.h> #endif
namespace { // Struct for sending a Mach message with a single port. struct MachSinglePortMessage {
mach_msg_header_t header;
mach_msg_body_t body;
mach_msg_port_descriptor_t data;
};
// Struct for receiving a Mach message with a single port. struct MachSinglePortMessageTrailer : MachSinglePortMessage {
mach_msg_audit_trailer_t trailer;
};
} // namespace
// The buffer must be big enough to store a full reply including // kMaxPassedMachSendRights port descriptors.
size_t buffer_size = sizeof(mach_msg_base_t) + sizeof(mach_msg_port_descriptor_t) *
mozilla::geckoargs::kMaxPassedMachSendRights + sizeof(mach_msg_trailer_t);
mozilla::UniquePtr<uint8_t[]> buffer =
mozilla::MakeUnique<uint8_t[]>(buffer_size);
// Send a single descriptor - the process mach_task_self() port.
MachSinglePortMessage* request = reinterpret_cast<MachSinglePortMessage*>(buffer.get());
request->header.msgh_bits =
MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE) |
MACH_MSGH_BITS_COMPLEX;
request->header.msgh_size = sizeof(MachSinglePortMessage);
request->header.msgh_remote_port = task_sender.get();
request->header.msgh_local_port = reply_port.get();
request->body.msgh_descriptor_count = 1;
request->data.type = MACH_MSG_PORT_DESCRIPTOR;
request->data.disposition = MACH_MSG_TYPE_COPY_SEND;
request->data.name = mach_task_self();
kr = mach_msg(&request->header,
MACH_SEND_MSG | MACH_RCV_MSG | MACH_SEND_TIMEOUT,
request->header.msgh_size, buffer_size,
request->header.msgh_local_port, timeout, MACH_PORT_NULL); if (kr != KERN_SUCCESS) { // NOTE: The request owns no ports, so we don't need to call // mach_msg_destroy on error here.
CHROMIUM_LOG(ERROR) << "child mach_msg failed: " << FormatMachError(kr); returnfalse;
}
mach_msg_port_descriptor_t* descrs = reinterpret_cast<mach_msg_port_descriptor_t*>(reply + 1); for (size_t i = 0; i < reply->body.msgh_descriptor_count; ++i) {
MOZ_RELEASE_ASSERT(descrs[i].type == MACH_MSG_PORT_DESCRIPTOR);
MOZ_RELEASE_ASSERT(descrs[i].disposition == MACH_MSG_TYPE_MOVE_SEND);
send_rights.emplace_back(descrs[i].name);
}
returntrue;
}
//==============================================================================
mozilla::Result<mozilla::Ok, mozilla::ipc::LaunchError>
MachHandleProcessCheckIn(
mach_port_t endpoint, pid_t child_pid, mach_msg_timeout_t timeout, const std::vector<mozilla::UniqueMachSendRight>& send_rights,
task_t* child_task) { using mozilla::Err; using mozilla::Ok; using mozilla::Result; using mozilla::ipc::LaunchError;
MOZ_ASSERT(send_rights.size() <= mozilla::geckoargs::kMaxPassedMachSendRights, "Child process cannot receive more than kMaxPassedMachSendRights " "during check-in!");
// Receive the check-in message from content. This will contain its 'task_t' // data, and a reply port which can be used to send the reply message.
MachSinglePortMessageTrailer request{};
request.header.msgh_size = sizeof(request);
request.header.msgh_local_port = endpoint;
// Ensure that the request from the new child process is cleaned up if we fail // in some way, such as to not leak any resources. auto destroyRequestMessage =
mozilla::MakeScopeExit([&] { mach_msg_destroy(&request.header); });
// Ensure the message was sent by the newly spawned child process. if (audit_token_to_pid(request.trailer.msgh_audit) != child_pid) {
CHROMIUM_LOG(ERROR) << "task_t was not sent by child process"; return Err(LaunchError("audit_token_to_pid"));
}
// Ensure the task_t corresponds to the newly spawned child process.
pid_t task_pid = -1;
kr = pid_for_task(request.data.name, &task_pid); if (kr != KERN_SUCCESS) {
CHROMIUM_LOG(ERROR) << "pid_for_task failed: " << FormatMachError(kr); return Err(LaunchError("pid_for_task", kr));
} if (task_pid != child_pid) {
CHROMIUM_LOG(ERROR) << "task_t is not for child process"; return Err(LaunchError("task_pid"));
}
// We've received the task_t for the correct process, reply to the message // with any send rights over to that child process which they should have on // startup.
size_t reply_size = sizeof(mach_msg_base_t) + sizeof(mach_msg_port_descriptor_t) * send_rights.size();
mozilla::UniquePtr<uint8_t[]> buffer =
mozilla::MakeUnique<uint8_t[]>(reply_size);
mach_msg_base_t* reply = reinterpret_cast<mach_msg_base_t*>(buffer.get());
reply->header.msgh_bits =
MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0) | MACH_MSGH_BITS_COMPLEX;
reply->header.msgh_size = reply_size;
reply->header.msgh_remote_port = request.header.msgh_remote_port;
reply->body.msgh_descriptor_count = send_rights.size();
// Fill the descriptors from our mChildArgs.
mach_msg_port_descriptor_t* descrs = reinterpret_cast<mach_msg_port_descriptor_t*>(reply + 1); for (size_t i = 0; i < send_rights.size(); ++i) {
descrs[i].type = MACH_MSG_PORT_DESCRIPTOR;
descrs[i].disposition = MACH_MSG_TYPE_COPY_SEND;
descrs[i].name = send_rights[i].get();
}
// Send the reply.
kr = mach_msg(&reply->header, MACH_SEND_MSG, reply->header.msgh_size, 0,
MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (kr != KERN_SUCCESS) { // NOTE: The only port which `mach_msg_destroy` would destroy is // `header.msgh_remote_port`, which is actually owned by `request`, so we // don't want to call `mach_msg_destroy` on the reply here. // // If we ever support passing receive rights, we'll need to make sure to // clean them up here, as their ownership must be moved into the message.
CHROMIUM_LOG(ERROR) << "parent mach_msg(MACH_SEND_MSG) failed: "
<< FormatMachError(kr); return Err(LaunchError("mach_msg(MACH_SEND_MSG)", kr));
}
// At this point, we've transferred the reply port, and are now taking the // mach task port from the request message (to pass to our caller), no longer // destroy the request message on error.
*child_task = request.data.name;
destroyRequestMessage.release();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.