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 12 namespace sandbox { 13 14 namespace { 15 16 #pragma pack(push, 4) 17 // Verified from launchd-329.3.3 (10.6.8). 18 struct 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 26 struct 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) 36 struct 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) 52 typedef int vproc_gsk_t; // Defined as an enum in liblaunch/vproc_priv.h. 53 struct 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. 63 size_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 72 uint64_t MachGetMessageID(const IPCMessage message) { 73 return message.mach->msgh_id; 74 } 75 76 template <typename R> 77 std::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 88 template <typename R> 89 void 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 101 template <typename R> 102 bool 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 109 const 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