| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "sandbox/mac/launchd_interception_server.h" | 5 #include "sandbox/mac/launchd_interception_server.h" |
| 6 | 6 |
| 7 #include <bsm/libbsm.h> | 7 #include <bsm/libbsm.h> |
| 8 #include <servers/bootstrap.h> | 8 #include <servers/bootstrap.h> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 69 } | 69 } |
| 70 reply_buffer_.reset(buffer, kBufferSize); | 70 reply_buffer_.reset(buffer, kBufferSize); |
| 71 | 71 |
| 72 // Allocate the dummy sandbox port. | 72 // Allocate the dummy sandbox port. |
| 73 if ((kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &port)) != | 73 if ((kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &port)) != |
| 74 KERN_SUCCESS) { | 74 KERN_SUCCESS) { |
| 75 MACH_LOG(ERROR, kr) << "Failed to allocate dummy sandbox port."; | 75 MACH_LOG(ERROR, kr) << "Failed to allocate dummy sandbox port."; |
| 76 return false; | 76 return false; |
| 77 } | 77 } |
| 78 sandbox_port_.reset(port); | 78 sandbox_port_.reset(port); |
| 79 if ((kr = mach_port_insert_right(task, sandbox_port_, sandbox_port_, |
| 80 MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS)) { |
| 81 MACH_LOG(ERROR, kr) << "Failed to allocate dummy sandbox port send right."; |
| 82 return false; |
| 83 } |
| 84 sandbox_send_port_.reset(sandbox_port_); |
| 79 | 85 |
| 80 // Set up the dispatch queue to service the bootstrap port. | 86 // Set up the dispatch queue to service the bootstrap port. |
| 81 // TODO(rsesek): Specify DISPATCH_QUEUE_SERIAL, in the 10.7 SDK. NULL means | 87 // TODO(rsesek): Specify DISPATCH_QUEUE_SERIAL, in the 10.7 SDK. NULL means |
| 82 // the same thing but is not symbolically clear. | 88 // the same thing but is not symbolically clear. |
| 83 server_queue_ = dispatch_queue_create( | 89 server_queue_ = dispatch_queue_create( |
| 84 "org.chromium.sandbox.LaunchdInterceptionServer", NULL); | 90 "org.chromium.sandbox.LaunchdInterceptionServer", NULL); |
| 85 server_source_ = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, | 91 server_source_ = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, |
| 86 server_port_.get(), 0, server_queue_); | 92 server_port_.get(), 0, server_queue_); |
| 87 dispatch_source_set_event_handler(server_source_, ^{ ReceiveMessage(); }); | 93 dispatch_source_set_event_handler(server_source_, ^{ ReceiveMessage(); }); |
| 88 dispatch_resume(server_source_); | 94 dispatch_resume(server_source_); |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 // or the one specified in the policy. | 215 // or the one specified in the policy. |
| 210 VLOG(1) << "Intercepting look_up2 with a sandboxed service port: " | 216 VLOG(1) << "Intercepting look_up2 with a sandboxed service port: " |
| 211 << request_service_name; | 217 << request_service_name; |
| 212 | 218 |
| 213 mach_port_t result_port; | 219 mach_port_t result_port; |
| 214 if (rule.result == POLICY_DENY_DUMMY_PORT) | 220 if (rule.result == POLICY_DENY_DUMMY_PORT) |
| 215 result_port = sandbox_port_.get(); | 221 result_port = sandbox_port_.get(); |
| 216 else | 222 else |
| 217 result_port = rule.substitute_port; | 223 result_port = rule.substitute_port; |
| 218 | 224 |
| 219 // Grant an additional send right on the result_port so that it can be | |
| 220 // sent to the sandboxed child process. | |
| 221 kern_return_t kr = mach_port_insert_right(mach_task_self(), | |
| 222 result_port, result_port, MACH_MSG_TYPE_MAKE_SEND); | |
| 223 if (kr != KERN_SUCCESS) { | |
| 224 MACH_LOG(ERROR, kr) << "Unable to insert right on result_port."; | |
| 225 } | |
| 226 | |
| 227 compat_shim_.look_up2_fill_reply(reply, result_port); | 225 compat_shim_.look_up2_fill_reply(reply, result_port); |
| 228 SendReply(reply); | 226 // If the message was sent successfully, clear the result_port out of the |
| 227 // message so that it is not destroyed at the end of ReceiveMessage. The |
| 228 // above-inserted right has been moved out of the process, and destroying |
| 229 // the message will unref yet another right. |
| 230 if (SendReply(reply)) |
| 231 compat_shim_.look_up2_fill_reply(reply, MACH_PORT_NULL); |
| 229 } else { | 232 } else { |
| 230 NOTREACHED(); | 233 NOTREACHED(); |
| 231 } | 234 } |
| 232 } | 235 } |
| 233 | 236 |
| 234 void LaunchdInterceptionServer::HandleSwapInteger(mach_msg_header_t* request, | 237 void LaunchdInterceptionServer::HandleSwapInteger(mach_msg_header_t* request, |
| 235 mach_msg_header_t* reply, | 238 mach_msg_header_t* reply, |
| 236 pid_t sender_pid) { | 239 pid_t sender_pid) { |
| 237 // Only allow getting information out of launchd. Do not allow setting | 240 // Only allow getting information out of launchd. Do not allow setting |
| 238 // values. Two commonly observed values that are retrieved are | 241 // values. Two commonly observed values that are retrieved are |
| 239 // VPROC_GSK_MGR_PID and VPROC_GSK_TRANSACTIONS_ENABLED. | 242 // VPROC_GSK_MGR_PID and VPROC_GSK_TRANSACTIONS_ENABLED. |
| 240 if (compat_shim_.swap_integer_is_get_only(request)) { | 243 if (compat_shim_.swap_integer_is_get_only(request)) { |
| 241 VLOG(2) << "Forwarding vproc swap_integer message."; | 244 VLOG(2) << "Forwarding vproc swap_integer message."; |
| 242 ForwardMessage(request, reply); | 245 ForwardMessage(request, reply); |
| 243 } else { | 246 } else { |
| 244 VLOG(2) << "Rejecting non-read-only swap_integer message."; | 247 VLOG(2) << "Rejecting non-read-only swap_integer message."; |
| 245 RejectMessage(request, reply, BOOTSTRAP_NOT_PRIVILEGED); | 248 RejectMessage(request, reply, BOOTSTRAP_NOT_PRIVILEGED); |
| 246 } | 249 } |
| 247 } | 250 } |
| 248 | 251 |
| 249 void LaunchdInterceptionServer::SendReply(mach_msg_header_t* reply) { | 252 bool LaunchdInterceptionServer::SendReply(mach_msg_header_t* reply) { |
| 250 kern_return_t kr = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, | 253 kern_return_t kr = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, |
| 251 MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | 254 MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); |
| 252 if (kr != KERN_SUCCESS) { | 255 MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr) |
| 253 MACH_LOG(ERROR, kr) << "Unable to send intercepted reply message."; | 256 << "Unable to send intercepted reply message."; |
| 254 } | 257 return kr == KERN_SUCCESS; |
| 255 } | 258 } |
| 256 | 259 |
| 257 void LaunchdInterceptionServer::ForwardMessage(mach_msg_header_t* request, | 260 void LaunchdInterceptionServer::ForwardMessage(mach_msg_header_t* request, |
| 258 mach_msg_header_t* reply) { | 261 mach_msg_header_t* reply) { |
| 259 request->msgh_local_port = request->msgh_remote_port; | 262 request->msgh_local_port = request->msgh_remote_port; |
| 260 request->msgh_remote_port = sandbox_->real_bootstrap_port(); | 263 request->msgh_remote_port = sandbox_->real_bootstrap_port(); |
| 261 // Preserve the msgh_bits that do not deal with the local and remote ports. | 264 // Preserve the msgh_bits that do not deal with the local and remote ports. |
| 262 request->msgh_bits = (request->msgh_bits & ~MACH_MSGH_BITS_PORTS_MASK) | | 265 request->msgh_bits = (request->msgh_bits & ~MACH_MSGH_BITS_PORTS_MASK) | |
| 263 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MOVE_SEND_ONCE); | 266 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MOVE_SEND_ONCE); |
| 264 kern_return_t kr = mach_msg_send(request); | 267 kern_return_t kr = mach_msg_send(request); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 275 mig_reply_error_t* error_reply = reinterpret_cast<mig_reply_error_t*>(reply); | 278 mig_reply_error_t* error_reply = reinterpret_cast<mig_reply_error_t*>(reply); |
| 276 error_reply->Head.msgh_size = sizeof(mig_reply_error_t); | 279 error_reply->Head.msgh_size = sizeof(mig_reply_error_t); |
| 277 error_reply->Head.msgh_bits = | 280 error_reply->Head.msgh_bits = |
| 278 MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND_ONCE); | 281 MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND_ONCE); |
| 279 error_reply->NDR = NDR_record; | 282 error_reply->NDR = NDR_record; |
| 280 error_reply->RetCode = error_code; | 283 error_reply->RetCode = error_code; |
| 281 SendReply(&error_reply->Head); | 284 SendReply(&error_reply->Head); |
| 282 } | 285 } |
| 283 | 286 |
| 284 } // namespace sandbox | 287 } // namespace sandbox |
| OLD | NEW |