• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
strnlen(const char * str,size_t maxlen)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 
MachGetMessageID(const IPCMessage message)72 uint64_t MachGetMessageID(const IPCMessage message) {
73   return message.mach->msgh_id;
74 }
75 
76 template <typename R>
LaunchdLookUp2GetRequestName(const IPCMessage message)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>
LaunchdLookUp2FillReply(IPCMessage message,mach_port_t port)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>
LaunchdSwapIntegerIsGetOnly(const IPCMessage message)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 
GetLaunchdCompatibilityShim()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