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. 4 5 #include "sandbox/mac/mach_message_server.h" 6 7 #include <bsm/libbsm.h> 8 #include <servers/bootstrap.h> 9 10 #include <string> 11 12 #include "base/logging.h" 13 #include "base/mac/mach_logging.h" 14 #include "base/strings/stringprintf.h" 15 #include "sandbox/mac/dispatch_source_mach.h" 16 17 namespace sandbox { 18 19 MachMessageServer::MachMessageServer( 20 MessageDemuxer* demuxer, 21 mach_port_t server_receive_right, 22 mach_msg_size_t buffer_size) 23 : demuxer_(demuxer), 24 server_port_(server_receive_right), 25 buffer_size_( 26 mach_vm_round_page(buffer_size + sizeof(mach_msg_audit_trailer_t))), 27 did_forward_message_(false) { 28 DCHECK(demuxer_); 29 } 30 31 MachMessageServer::~MachMessageServer() { 32 } 33 34 bool MachMessageServer::Initialize() { 35 mach_port_t task = mach_task_self(); 36 kern_return_t kr; 37 38 // Allocate a port for use as a new server port if one was not passed to the 39 // constructor. 40 if (!server_port_.is_valid()) { 41 mach_port_t port; 42 if ((kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &port)) != 43 KERN_SUCCESS) { 44 MACH_LOG(ERROR, kr) << "Failed to allocate new server port."; 45 return false; 46 } 47 server_port_.reset(port); 48 } 49 50 // Allocate the message request and reply buffers. 51 const int kMachMsgMemoryFlags = VM_MAKE_TAG(VM_MEMORY_MACH_MSG) | 52 VM_FLAGS_ANYWHERE; 53 vm_address_t buffer = 0; 54 55 kr = vm_allocate(task, &buffer, buffer_size_, kMachMsgMemoryFlags); 56 if (kr != KERN_SUCCESS) { 57 MACH_LOG(ERROR, kr) << "Failed to allocate request buffer."; 58 return false; 59 } 60 request_buffer_.reset(buffer, buffer_size_); 61 62 kr = vm_allocate(task, &buffer, buffer_size_, kMachMsgMemoryFlags); 63 if (kr != KERN_SUCCESS) { 64 MACH_LOG(ERROR, kr) << "Failed to allocate reply buffer."; 65 return false; 66 } 67 reply_buffer_.reset(buffer, buffer_size_); 68 69 // Set up the dispatch queue to service the bootstrap port. 70 std::string label = base::StringPrintf( 71 "org.chromium.sandbox.MachMessageServer.%p", demuxer_); 72 dispatch_source_.reset(new DispatchSourceMach( 73 label.c_str(), server_port_.get(), ^{ ReceiveMessage(); })); 74 dispatch_source_->Resume(); 75 76 return true; 77 } 78 79 pid_t MachMessageServer::GetMessageSenderPID(IPCMessage request) { 80 // Get the PID of the task that sent this request. This requires getting at 81 // the trailer of the message, from the header. 82 mach_msg_audit_trailer_t* trailer = 83 reinterpret_cast<mach_msg_audit_trailer_t*>( 84 reinterpret_cast<vm_address_t>(request.mach) + 85 round_msg(request.mach->msgh_size)); 86 // TODO(rsesek): In the 10.7 SDK, there's audit_token_to_pid(). 87 pid_t sender_pid; 88 audit_token_to_au32(trailer->msgh_audit, 89 NULL, NULL, NULL, NULL, NULL, &sender_pid, NULL, NULL); 90 return sender_pid; 91 } 92 93 IPCMessage MachMessageServer::CreateReply(IPCMessage request_message) { 94 mach_msg_header_t* request = request_message.mach; 95 96 IPCMessage reply_message; 97 mach_msg_header_t* reply = reply_message.mach = 98 reinterpret_cast<mach_msg_header_t*>(reply_buffer_.address()); 99 bzero(reply, buffer_size_); 100 101 reply->msgh_bits = MACH_MSGH_BITS_REMOTE(reply->msgh_bits); 102 // Since mach_msg will automatically swap the request and reply ports, 103 // undo that. 104 reply->msgh_remote_port = request->msgh_remote_port; 105 reply->msgh_local_port = MACH_PORT_NULL; 106 // MIG servers simply add 100 to the request ID to generate the reply ID. 107 reply->msgh_id = request->msgh_id + 100; 108 109 return reply_message; 110 } 111 112 bool MachMessageServer::SendReply(IPCMessage reply) { 113 kern_return_t kr = mach_msg(reply.mach, MACH_SEND_MSG, 114 reply.mach->msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, 115 MACH_PORT_NULL); 116 MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr) 117 << "Unable to send intercepted reply message."; 118 return kr == KERN_SUCCESS; 119 } 120 121 void MachMessageServer::ForwardMessage(IPCMessage message, 122 mach_port_t destination) { 123 mach_msg_header_t* request = message.mach; 124 request->msgh_local_port = request->msgh_remote_port; 125 request->msgh_remote_port = destination; 126 // Preserve the msgh_bits that do not deal with the local and remote ports. 127 request->msgh_bits = (request->msgh_bits & ~MACH_MSGH_BITS_PORTS_MASK) | 128 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MOVE_SEND_ONCE); 129 kern_return_t kr = mach_msg_send(request); 130 if (kr == KERN_SUCCESS) { 131 did_forward_message_ = true; 132 } else { 133 MACH_LOG(ERROR, kr) << "Unable to forward message to the real launchd."; 134 } 135 } 136 137 void MachMessageServer::RejectMessage(IPCMessage request, int error_code) { 138 IPCMessage reply = CreateReply(request); 139 mig_reply_error_t* error_reply = 140 reinterpret_cast<mig_reply_error_t*>(reply.mach); 141 error_reply->Head.msgh_size = sizeof(mig_reply_error_t); 142 error_reply->Head.msgh_bits = 143 MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND_ONCE); 144 error_reply->NDR = NDR_record; 145 error_reply->RetCode = error_code; 146 SendReply(reply); 147 } 148 149 mach_port_t MachMessageServer::GetServerPort() const { 150 return server_port_.get(); 151 } 152 153 void MachMessageServer::ReceiveMessage() { 154 const mach_msg_options_t kRcvOptions = MACH_RCV_MSG | 155 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) | 156 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT); 157 158 mach_msg_header_t* request = 159 reinterpret_cast<mach_msg_header_t*>(request_buffer_.address()); 160 mach_msg_header_t* reply = 161 reinterpret_cast<mach_msg_header_t*>(reply_buffer_.address()); 162 163 // Zero out the buffers from handling any previous message. 164 bzero(request, buffer_size_); 165 bzero(reply, buffer_size_); 166 did_forward_message_ = false; 167 168 // A Mach message server-once. The system library to run a message server 169 // cannot be used here, because some requests are conditionally forwarded 170 // to another server. 171 kern_return_t kr = mach_msg(request, kRcvOptions, 0, buffer_size_, 172 server_port_.get(), MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); 173 if (kr != KERN_SUCCESS) { 174 MACH_LOG(ERROR, kr) << "Unable to receive message."; 175 return; 176 } 177 178 // Process the message. 179 IPCMessage request_message = { request }; 180 demuxer_->DemuxMessage(request_message); 181 182 // Free any descriptors in the message body. If the message was forwarded, 183 // any descriptors would have been moved out of the process on send. If the 184 // forwarded message was sent from the process hosting this sandbox server, 185 // destroying the message could also destroy rights held outside the scope of 186 // this message server. 187 if (!did_forward_message_) { 188 mach_msg_destroy(request); 189 mach_msg_destroy(reply); 190 } 191 } 192 193 } // namespace sandbox 194