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