Revert of Remove media::VideoRenderer::SetPlaybackRate(). (https://codereview.chromiu...
[chromium-blink-merge.git] / sandbox / mac / mach_message_server.cc
blobfd16b6d7b709a75129ea299412b680053bd145e9
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "sandbox/mac/mach_message_server.h"
7 #include <bsm/libbsm.h>
8 #include <servers/bootstrap.h>
10 #include <string>
12 #include "base/logging.h"
13 #include "base/mac/mach_logging.h"
14 #include "base/strings/stringprintf.h"
16 namespace sandbox {
18 MachMessageServer::MachMessageServer(
19 MessageDemuxer* demuxer,
20 mach_port_t server_receive_right,
21 mach_msg_size_t buffer_size)
22 : demuxer_(demuxer),
23 server_port_(server_receive_right),
24 server_queue_(NULL),
25 server_source_(NULL),
26 source_canceled_(dispatch_semaphore_create(0)),
27 buffer_size_(
28 mach_vm_round_page(buffer_size + sizeof(mach_msg_audit_trailer_t))),
29 did_forward_message_(false) {
30 DCHECK(demuxer_);
33 MachMessageServer::~MachMessageServer() {
34 if (server_source_) {
35 dispatch_source_cancel(server_source_);
36 dispatch_release(server_source_);
38 dispatch_semaphore_wait(source_canceled_, DISPATCH_TIME_FOREVER);
39 dispatch_release(source_canceled_);
41 if (server_queue_)
42 dispatch_release(server_queue_);
45 bool MachMessageServer::Initialize() {
46 mach_port_t task = mach_task_self();
47 kern_return_t kr;
49 // Allocate a port for use as a new server port if one was not passed to the
50 // constructor.
51 if (!server_port_.is_valid()) {
52 mach_port_t port;
53 if ((kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &port)) !=
54 KERN_SUCCESS) {
55 MACH_LOG(ERROR, kr) << "Failed to allocate new server port.";
56 return false;
58 server_port_.reset(port);
61 // Allocate the message request and reply buffers.
62 const int kMachMsgMemoryFlags = VM_MAKE_TAG(VM_MEMORY_MACH_MSG) |
63 VM_FLAGS_ANYWHERE;
64 vm_address_t buffer = 0;
66 kr = vm_allocate(task, &buffer, buffer_size_, kMachMsgMemoryFlags);
67 if (kr != KERN_SUCCESS) {
68 MACH_LOG(ERROR, kr) << "Failed to allocate request buffer.";
69 return false;
71 request_buffer_.reset(buffer, buffer_size_);
73 kr = vm_allocate(task, &buffer, buffer_size_, kMachMsgMemoryFlags);
74 if (kr != KERN_SUCCESS) {
75 MACH_LOG(ERROR, kr) << "Failed to allocate reply buffer.";
76 return false;
78 reply_buffer_.reset(buffer, buffer_size_);
80 // Set up the dispatch queue to service the bootstrap port.
81 // TODO(rsesek): Specify DISPATCH_QUEUE_SERIAL, in the 10.7 SDK. NULL means
82 // the same thing but is not symbolically clear.
83 std::string label = base::StringPrintf(
84 "org.chromium.sandbox.MachMessageServer.%p", demuxer_);
85 server_queue_ = dispatch_queue_create(label.c_str(), NULL);
86 server_source_ = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV,
87 server_port_.get(), 0, server_queue_);
88 dispatch_source_set_event_handler(server_source_, ^{ ReceiveMessage(); });
89 dispatch_source_set_cancel_handler(server_source_, ^{
90 dispatch_semaphore_signal(source_canceled_);
91 });
92 dispatch_resume(server_source_);
94 return true;
97 pid_t MachMessageServer::GetMessageSenderPID(IPCMessage request) {
98 // Get the PID of the task that sent this request. This requires getting at
99 // the trailer of the message, from the header.
100 mach_msg_audit_trailer_t* trailer =
101 reinterpret_cast<mach_msg_audit_trailer_t*>(
102 reinterpret_cast<vm_address_t>(request.mach) +
103 round_msg(request.mach->msgh_size));
104 // TODO(rsesek): In the 10.7 SDK, there's audit_token_to_pid().
105 pid_t sender_pid;
106 audit_token_to_au32(trailer->msgh_audit,
107 NULL, NULL, NULL, NULL, NULL, &sender_pid, NULL, NULL);
108 return sender_pid;
111 bool MachMessageServer::SendReply(IPCMessage reply) {
112 kern_return_t kr = mach_msg(reply.mach, MACH_SEND_MSG,
113 reply.mach->msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
114 MACH_PORT_NULL);
115 MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
116 << "Unable to send intercepted reply message.";
117 return kr == KERN_SUCCESS;
120 void MachMessageServer::ForwardMessage(IPCMessage message,
121 mach_port_t destination) {
122 mach_msg_header_t* request = message.mach;
123 request->msgh_local_port = request->msgh_remote_port;
124 request->msgh_remote_port = destination;
125 // Preserve the msgh_bits that do not deal with the local and remote ports.
126 request->msgh_bits = (request->msgh_bits & ~MACH_MSGH_BITS_PORTS_MASK) |
127 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MOVE_SEND_ONCE);
128 kern_return_t kr = mach_msg_send(request);
129 if (kr == KERN_SUCCESS) {
130 did_forward_message_ = true;
131 } else {
132 MACH_LOG(ERROR, kr) << "Unable to forward message to the real launchd.";
136 void MachMessageServer::RejectMessage(IPCMessage reply, int error_code) {
137 mig_reply_error_t* error_reply =
138 reinterpret_cast<mig_reply_error_t*>(reply.mach);
139 error_reply->Head.msgh_size = sizeof(mig_reply_error_t);
140 error_reply->Head.msgh_bits =
141 MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND_ONCE);
142 error_reply->NDR = NDR_record;
143 error_reply->RetCode = error_code;
144 SendReply(reply);
147 mach_port_t MachMessageServer::GetServerPort() const {
148 return server_port_.get();
151 void MachMessageServer::ReceiveMessage() {
152 const mach_msg_options_t kRcvOptions = MACH_RCV_MSG |
153 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
154 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT);
156 mach_msg_header_t* request =
157 reinterpret_cast<mach_msg_header_t*>(request_buffer_.address());
158 mach_msg_header_t* reply =
159 reinterpret_cast<mach_msg_header_t*>(reply_buffer_.address());
161 // Zero out the buffers from handling any previous message.
162 bzero(request, buffer_size_);
163 bzero(reply, buffer_size_);
164 did_forward_message_ = false;
166 // A Mach message server-once. The system library to run a message server
167 // cannot be used here, because some requests are conditionally forwarded
168 // to another server.
169 kern_return_t kr = mach_msg(request, kRcvOptions, 0, buffer_size_,
170 server_port_.get(), MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
171 if (kr != KERN_SUCCESS) {
172 MACH_LOG(ERROR, kr) << "Unable to receive message.";
173 return;
176 // Set up a reply message in case it will be used.
177 reply->msgh_bits = MACH_MSGH_BITS_REMOTE(reply->msgh_bits);
178 // Since mach_msg will automatically swap the request and reply ports,
179 // undo that.
180 reply->msgh_remote_port = request->msgh_remote_port;
181 reply->msgh_local_port = MACH_PORT_NULL;
182 // MIG servers simply add 100 to the request ID to generate the reply ID.
183 reply->msgh_id = request->msgh_id + 100;
185 // Process the message.
186 IPCMessage request_message = { request };
187 IPCMessage reply_message = { reply };
188 demuxer_->DemuxMessage(request_message, reply_message);
190 // Free any descriptors in the message body. If the message was forwarded,
191 // any descriptors would have been moved out of the process on send. If the
192 // forwarded message was sent from the process hosting this sandbox server,
193 // destroying the message could also destroy rights held outside the scope of
194 // this message server.
195 if (!did_forward_message_) {
196 mach_msg_destroy(request);
197 mach_msg_destroy(reply);
201 } // namespace sandbox