Home | History | Annotate | Download | only in mac
      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.
     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 
     72 uint64_t MachGetMessageID(const IPCMessage message) {
     73   return message.mach->msgh_id;
     74 }
     75 
     76 template <typename R>
     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>
     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>
    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 
    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