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/os_compatibility.h" 6 7#include <servers/bootstrap.h> 8#include <unistd.h> 9 10#include "base/mac/mac_util.h" 11 12namespace sandbox { 13 14namespace { 15 16// Verified from launchd-329.3.3 (10.6.8). 17struct look_up2_request_10_6 { 18 mach_msg_header_t Head; 19 NDR_record_t NDR; 20 name_t servicename; 21 pid_t targetpid; 22 uint64_t flags; 23}; 24 25struct look_up2_reply_10_6 { 26 mach_msg_header_t Head; 27 mach_msg_body_t msgh_body; 28 mach_msg_port_descriptor_t service_port; 29}; 30 31// Verified from: 32// launchd-392.39 (10.7.5) 33// launchd-442.26.2 (10.8.5) 34// launchd-842.1.4 (10.9.0) 35struct look_up2_request_10_7 { 36 mach_msg_header_t Head; 37 NDR_record_t NDR; 38 name_t servicename; 39 pid_t targetpid; 40 uuid_t instanceid; 41 uint64_t flags; 42}; 43 44// look_up2_reply_10_7 is the same as the 10_6 version. 45 46// Verified from: 47// launchd-329.3.3 (10.6.8) 48// launchd-392.39 (10.7.5) 49// launchd-442.26.2 (10.8.5) 50// launchd-842.1.4 (10.9.0) 51typedef int vproc_gsk_t; // Defined as an enum in liblaunch/vproc_priv.h. 52struct swap_integer_request_10_6 { 53 mach_msg_header_t Head; 54 NDR_record_t NDR; 55 vproc_gsk_t inkey; 56 vproc_gsk_t outkey; 57 int64_t inval; 58}; 59 60// TODO(rsesek): Libc provides strnlen() starting in 10.7. 61size_t strnlen(const char* str, size_t maxlen) { 62 size_t len = 0; 63 for (; len < maxlen; ++len, ++str) { 64 if (*str == '\0') 65 break; 66 } 67 return len; 68} 69 70template <typename R> 71std::string LaunchdLookUp2GetRequestName(const mach_msg_header_t* header) { 72 DCHECK_EQ(sizeof(R), header->msgh_size); 73 const R* request = reinterpret_cast<const R*>(header); 74 // Make sure the name is properly NUL-terminated. 75 const size_t name_length = 76 strnlen(request->servicename, BOOTSTRAP_MAX_NAME_LEN); 77 std::string name = std::string(request->servicename, name_length); 78 return name; 79} 80 81template <typename R> 82void LaunchdLookUp2FillReply(mach_msg_header_t* header, mach_port_t port) { 83 R* reply = reinterpret_cast<R*>(header); 84 reply->Head.msgh_size = sizeof(R); 85 reply->Head.msgh_bits = 86 MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND_ONCE) | 87 MACH_MSGH_BITS_COMPLEX; 88 reply->msgh_body.msgh_descriptor_count = 1; 89 reply->service_port.name = port; 90 reply->service_port.disposition = MACH_MSG_TYPE_COPY_SEND; 91 reply->service_port.type = MACH_MSG_PORT_DESCRIPTOR; 92} 93 94template <typename R> 95bool LaunchdSwapIntegerIsGetOnly(const mach_msg_header_t* header) { 96 const R* request = reinterpret_cast<const R*>(header); 97 return request->inkey == 0 && request->inval == 0 && request->outkey != 0; 98} 99 100} // namespace 101 102const LaunchdCompatibilityShim GetLaunchdCompatibilityShim() { 103 LaunchdCompatibilityShim shim = { 104 .msg_id_look_up2 = 404, 105 .msg_id_swap_integer = 416, 106 .look_up2_fill_reply = &LaunchdLookUp2FillReply<look_up2_reply_10_6>, 107 .swap_integer_is_get_only = 108 &LaunchdSwapIntegerIsGetOnly<swap_integer_request_10_6>, 109 }; 110 111 if (base::mac::IsOSSnowLeopard()) { 112 shim.look_up2_get_request_name = 113 &LaunchdLookUp2GetRequestName<look_up2_request_10_6>; 114 } else if (base::mac::IsOSLionOrLater() && 115 !base::mac::IsOSYosemiteOrLater()) { 116 shim.look_up2_get_request_name = 117 &LaunchdLookUp2GetRequestName<look_up2_request_10_7>; 118 } else { 119 DLOG(ERROR) << "Unknown OS, using launchd compatibility shim from 10.7."; 120 shim.look_up2_get_request_name = 121 &LaunchdLookUp2GetRequestName<look_up2_request_10_7>; 122 } 123 124 return shim; 125} 126 127} // namespace sandbox 128