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>
10 #include "base/mac/mac_util.h"
11 #include "sandbox/mac/xpc.h"
18 // Verified from launchd-329.3.3 (10.6.8).
19 struct look_up2_request_10_6
{
20 mach_msg_header_t Head
;
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
;
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
;
46 // look_up2_reply_10_7 is the same as the 10_6 version.
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
;
63 // TODO(rsesek): Libc provides strnlen() starting in 10.7.
64 size_t strnlen(const char* str
, size_t maxlen
) {
66 for (; len
< maxlen
; ++len
, ++str
) {
73 class OSCompatibility_10_6
: public OSCompatibility
{
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
{
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
{
117 reinterpret_cast<const swap_integer_request_10_6
*>(message
.mach
);
118 return request
->inkey
== 0 && request
->inval
== 0 && request
->outkey
!= 0;
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
);
137 class OSCompatibility_10_7
: public OSCompatibility_10_6
{
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
{
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;
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());
204 return make_scoped_ptr(new OSCompatibility_10_10());
207 OSCompatibility::~OSCompatibility() {}
209 } // namespace sandbox