// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "sandbox/mac/os_compatibility.h" #include #include #include #include #include "base/mac/mac_util.h" #include "sandbox/mac/xpc.h" namespace sandbox { namespace { #pragma pack(push, 4) // Verified from launchd-329.3.3 (10.6.8). struct look_up2_request_10_6 { mach_msg_header_t Head; NDR_record_t NDR; name_t servicename; pid_t targetpid; uint64_t flags; }; struct look_up2_reply_10_6 { mach_msg_header_t Head; mach_msg_body_t msgh_body; mach_msg_port_descriptor_t service_port; }; // Verified from: // launchd-392.39 (10.7.5) // launchd-442.26.2 (10.8.5) // launchd-842.1.4 (10.9.0) struct look_up2_request_10_7 { mach_msg_header_t Head; NDR_record_t NDR; name_t servicename; pid_t targetpid; uuid_t instanceid; uint64_t flags; }; // look_up2_reply_10_7 is the same as the 10_6 version. // Verified from: // launchd-329.3.3 (10.6.8) // launchd-392.39 (10.7.5) // launchd-442.26.2 (10.8.5) // launchd-842.1.4 (10.9.0) typedef int vproc_gsk_t; // Defined as an enum in liblaunch/vproc_priv.h. struct swap_integer_request_10_6 { mach_msg_header_t Head; NDR_record_t NDR; vproc_gsk_t inkey; vproc_gsk_t outkey; int64_t inval; }; #pragma pack(pop) // TODO(rsesek): Libc provides strnlen() starting in 10.7. size_t strnlen(const char* str, size_t maxlen) { size_t len = 0; for (; len < maxlen; ++len, ++str) { if (*str == '\0') break; } return len; } class OSCompatibility_10_6 : public OSCompatibility { public: OSCompatibility_10_6() {} ~OSCompatibility_10_6() override {} uint64_t GetMessageSubsystem(const IPCMessage message) override { return (message.mach->msgh_id / 100) * 100; } uint64_t GetMessageID(const IPCMessage message) override { return message.mach->msgh_id; } bool IsServiceLookUpRequest(const IPCMessage message) override { return GetMessageID(message) == 404; } bool IsVprocSwapInteger(const IPCMessage message) override { return GetMessageID(message) == 416; } bool IsXPCDomainManagement(const IPCMessage message) override { return false; } std::string GetServiceLookupName(const IPCMessage message) override { return GetRequestName(message); } void WriteServiceLookUpReply(IPCMessage message, mach_port_t service_port) override { auto reply = reinterpret_cast(message.mach); reply->Head.msgh_size = sizeof(*reply); reply->Head.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND_ONCE) | MACH_MSGH_BITS_COMPLEX; reply->msgh_body.msgh_descriptor_count = 1; reply->service_port.name = service_port; reply->service_port.disposition = MACH_MSG_TYPE_COPY_SEND; reply->service_port.type = MACH_MSG_PORT_DESCRIPTOR; } bool IsSwapIntegerReadOnly(const IPCMessage message) override { auto request = reinterpret_cast(message.mach); return request->inkey == 0 && request->inval == 0 && request->outkey != 0; } protected: // The 10.6 and 10.7 implementations are the same except for struct offsets, // so provide this templatized helper. template static std::string GetRequestName(const IPCMessage message) { mach_msg_header_t* header = message.mach; DCHECK_EQ(sizeof(R), header->msgh_size); const R* request = reinterpret_cast(header); // Make sure the name is properly NUL-terminated. const size_t name_length = strnlen(request->servicename, BOOTSTRAP_MAX_NAME_LEN); std::string name = std::string(request->servicename, name_length); return name; } }; class OSCompatibility_10_7 : public OSCompatibility_10_6 { public: OSCompatibility_10_7() {} ~OSCompatibility_10_7() override {} std::string GetServiceLookupName(const IPCMessage message) override { return GetRequestName(message); } }; class OSCompatibility_10_10 : public OSCompatibility { public: OSCompatibility_10_10() {} ~OSCompatibility_10_10() override {} uint64_t GetMessageSubsystem(const IPCMessage message) override { return xpc_dictionary_get_uint64(message.xpc, "subsystem"); } uint64_t GetMessageID(const IPCMessage message) override { return xpc_dictionary_get_uint64(message.xpc, "routine"); } bool IsServiceLookUpRequest(const IPCMessage message) override { uint64_t subsystem = GetMessageSubsystem(message); uint64_t id = GetMessageID(message); // Lookup requests in XPC can either go through the Mach bootstrap subsytem // (5) from bootstrap_look_up(), or the XPC domain subsystem (3) for // xpc_connection_create(). Both use the same message format. return (subsystem == 5 && id == 207) || (subsystem == 3 && id == 804); } bool IsVprocSwapInteger(const IPCMessage message) override { return GetMessageSubsystem(message) == 6 && GetMessageID(message) == 301; } bool IsXPCDomainManagement(const IPCMessage message) override { return GetMessageSubsystem(message) == 3; } std::string GetServiceLookupName(const IPCMessage message) override { const char* name = xpc_dictionary_get_string(message.xpc, "name"); const size_t name_length = strnlen(name, BOOTSTRAP_MAX_NAME_LEN); return std::string(name, name_length); } void WriteServiceLookUpReply(IPCMessage message, mach_port_t service_port) override { xpc_dictionary_set_mach_send(message.xpc, "port", service_port); } bool IsSwapIntegerReadOnly(const IPCMessage message) override { return xpc_dictionary_get_bool(message.xpc, "set") == false && xpc_dictionary_get_uint64(message.xpc, "ingsk") == 0 && xpc_dictionary_get_int64(message.xpc, "in") == 0; } }; } // namespace // static scoped_ptr OSCompatibility::CreateForPlatform() { if (base::mac::IsOSSnowLeopard()) return make_scoped_ptr(new OSCompatibility_10_6()); else if (base::mac::IsOSLionOrLater() && base::mac::IsOSMavericksOrEarlier()) return make_scoped_ptr(new OSCompatibility_10_7()); else return make_scoped_ptr(new OSCompatibility_10_10()); } OSCompatibility::~OSCompatibility() {} } // namespace sandbox