Courgette: Skip the relocs that live outside of the image.
[chromium-blink-merge.git] / sandbox / mac / os_compatibility.cc
blobf1ad5286a16f9db9a139e1c38eb66a7778391b4d
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.
5 #include "sandbox/mac/os_compatibility.h"
7 #include <servers/bootstrap.h>
8 #include <unistd.h>
10 #include "base/mac/mac_util.h"
11 #include "sandbox/mac/xpc.h"
13 namespace sandbox {
15 namespace {
17 #pragma pack(push, 4)
18 // Verified from launchd-329.3.3 (10.6.8).
19 struct look_up2_request_10_6 {
20 mach_msg_header_t Head;
21 NDR_record_t NDR;
22 name_t servicename;
23 pid_t targetpid;
24 uint64_t flags;
27 struct look_up2_reply_10_6 {
28 mach_msg_header_t Head;
29 mach_msg_body_t msgh_body;
30 mach_msg_port_descriptor_t service_port;
33 // Verified from:
34 // launchd-392.39 (10.7.5)
35 // launchd-442.26.2 (10.8.5)
36 // launchd-842.1.4 (10.9.0)
37 struct look_up2_request_10_7 {
38 mach_msg_header_t Head;
39 NDR_record_t NDR;
40 name_t servicename;
41 pid_t targetpid;
42 uuid_t instanceid;
43 uint64_t flags;
46 // look_up2_reply_10_7 is the same as the 10_6 version.
48 // Verified from:
49 // launchd-329.3.3 (10.6.8)
50 // launchd-392.39 (10.7.5)
51 // launchd-442.26.2 (10.8.5)
52 // launchd-842.1.4 (10.9.0)
53 typedef int vproc_gsk_t; // Defined as an enum in liblaunch/vproc_priv.h.
54 struct swap_integer_request_10_6 {
55 mach_msg_header_t Head;
56 NDR_record_t NDR;
57 vproc_gsk_t inkey;
58 vproc_gsk_t outkey;
59 int64_t inval;
61 #pragma pack(pop)
63 // TODO(rsesek): Libc provides strnlen() starting in 10.7.
64 size_t strnlen(const char* str, size_t maxlen) {
65 size_t len = 0;
66 for (; len < maxlen; ++len, ++str) {
67 if (*str == '\0')
68 break;
70 return len;
73 class OSCompatibility_10_6 : public OSCompatibility {
74 public:
75 OSCompatibility_10_6() {}
76 ~OSCompatibility_10_6() override {}
78 uint64_t GetMessageSubsystem(const IPCMessage message) override {
79 return (message.mach->msgh_id / 100) * 100;
82 uint64_t GetMessageID(const IPCMessage message) override {
83 return message.mach->msgh_id;
86 bool IsServiceLookUpRequest(const IPCMessage message) override {
87 return GetMessageID(message) == 404;
90 bool IsVprocSwapInteger(const IPCMessage message) override {
91 return GetMessageID(message) == 416;
94 bool IsXPCDomainManagement(const IPCMessage message) override {
95 return false;
98 std::string GetServiceLookupName(const IPCMessage message) override {
99 return GetRequestName<look_up2_request_10_6>(message);
102 void WriteServiceLookUpReply(IPCMessage message,
103 mach_port_t service_port) override {
104 auto reply = reinterpret_cast<look_up2_reply_10_6*>(message.mach);
105 reply->Head.msgh_size = sizeof(*reply);
106 reply->Head.msgh_bits =
107 MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND_ONCE) |
108 MACH_MSGH_BITS_COMPLEX;
109 reply->msgh_body.msgh_descriptor_count = 1;
110 reply->service_port.name = service_port;
111 reply->service_port.disposition = MACH_MSG_TYPE_COPY_SEND;
112 reply->service_port.type = MACH_MSG_PORT_DESCRIPTOR;
115 bool IsSwapIntegerReadOnly(const IPCMessage message) override {
116 auto request =
117 reinterpret_cast<const swap_integer_request_10_6*>(message.mach);
118 return request->inkey == 0 && request->inval == 0 && request->outkey != 0;
121 protected:
122 // The 10.6 and 10.7 implementations are the same except for struct offsets,
123 // so provide this templatized helper.
124 template <typename R>
125 static std::string GetRequestName(const IPCMessage message) {
126 mach_msg_header_t* header = message.mach;
127 DCHECK_EQ(sizeof(R), header->msgh_size);
128 const R* request = reinterpret_cast<const R*>(header);
129 // Make sure the name is properly NUL-terminated.
130 const size_t name_length =
131 strnlen(request->servicename, BOOTSTRAP_MAX_NAME_LEN);
132 std::string name = std::string(request->servicename, name_length);
133 return name;
137 class OSCompatibility_10_7 : public OSCompatibility_10_6 {
138 public:
139 OSCompatibility_10_7() {}
140 ~OSCompatibility_10_7() override {}
142 std::string GetServiceLookupName(const IPCMessage message) override {
143 return GetRequestName<look_up2_request_10_7>(message);
147 class OSCompatibility_10_10 : public OSCompatibility {
148 public:
149 OSCompatibility_10_10() {}
150 ~OSCompatibility_10_10() override {}
152 uint64_t GetMessageSubsystem(const IPCMessage message) override {
153 return xpc_dictionary_get_uint64(message.xpc, "subsystem");
156 uint64_t GetMessageID(const IPCMessage message) override {
157 return xpc_dictionary_get_uint64(message.xpc, "routine");
160 bool IsServiceLookUpRequest(const IPCMessage message) override {
161 uint64_t subsystem = GetMessageSubsystem(message);
162 uint64_t id = GetMessageID(message);
163 // Lookup requests in XPC can either go through the Mach bootstrap subsytem
164 // (5) from bootstrap_look_up(), or the XPC domain subsystem (3) for
165 // xpc_connection_create(). Both use the same message format.
166 return (subsystem == 5 && id == 207) || (subsystem == 3 && id == 804);
169 bool IsVprocSwapInteger(const IPCMessage message) override {
170 return GetMessageSubsystem(message) == 6 && GetMessageID(message) == 301;
173 bool IsXPCDomainManagement(const IPCMessage message) override {
174 return GetMessageSubsystem(message) == 3;
177 std::string GetServiceLookupName(const IPCMessage message) override {
178 const char* name = xpc_dictionary_get_string(message.xpc, "name");
179 const size_t name_length = strnlen(name, BOOTSTRAP_MAX_NAME_LEN);
180 return std::string(name, name_length);
183 void WriteServiceLookUpReply(IPCMessage message,
184 mach_port_t service_port) override {
185 xpc_dictionary_set_mach_send(message.xpc, "port", service_port);
188 bool IsSwapIntegerReadOnly(const IPCMessage message) override {
189 return xpc_dictionary_get_bool(message.xpc, "set") == false &&
190 xpc_dictionary_get_uint64(message.xpc, "ingsk") == 0 &&
191 xpc_dictionary_get_int64(message.xpc, "in") == 0;
195 } // namespace
197 // static
198 scoped_ptr<OSCompatibility> OSCompatibility::CreateForPlatform() {
199 if (base::mac::IsOSSnowLeopard())
200 return make_scoped_ptr(new OSCompatibility_10_6());
201 else if (base::mac::IsOSLionOrLater() && base::mac::IsOSMavericksOrEarlier())
202 return make_scoped_ptr(new OSCompatibility_10_7());
203 else
204 return make_scoped_ptr(new OSCompatibility_10_10());
207 OSCompatibility::~OSCompatibility() {}
209 } // namespace sandbox