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 // Verified from launchd-329.3.3 (10.6.8). 17 struct 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 25 struct 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) 35 struct 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) 51 typedef int vproc_gsk_t; // Defined as an enum in liblaunch/vproc_priv.h. 52 struct 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. 61 size_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 70 template <typename R> 71 std::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 81 template <typename R> 82 void 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 94 template <typename R> 95 bool 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 102 const 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