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 // Verified from launchd-329.3.3 (10.6.8).
     17 struct look_up2_request_10_6 {
     18   mach_msg_header_t Head;
     19   NDR_record_t NDR;
     20   name_t servicename;
     21   pid_t targetpid;
     22   uint64_t flags;
     23 };
     24 
     25 struct look_up2_reply_10_6 {
     26   mach_msg_header_t Head;
     27   mach_msg_body_t msgh_body;
     28   mach_msg_port_descriptor_t service_port;
     29 };
     30 
     31 // Verified from:
     32 //   launchd-392.39 (10.7.5)
     33 //   launchd-442.26.2 (10.8.5)
     34 //   launchd-842.1.4 (10.9.0)
     35 struct look_up2_request_10_7 {
     36   mach_msg_header_t Head;
     37   NDR_record_t NDR;
     38   name_t servicename;
     39   pid_t targetpid;
     40   uuid_t instanceid;
     41   uint64_t flags;
     42 };
     43 
     44 // look_up2_reply_10_7 is the same as the 10_6 version.
     45 
     46 // Verified from:
     47 //   launchd-329.3.3 (10.6.8)
     48 //   launchd-392.39 (10.7.5)
     49 //   launchd-442.26.2 (10.8.5)
     50 //   launchd-842.1.4 (10.9.0)
     51 typedef int vproc_gsk_t;  // Defined as an enum in liblaunch/vproc_priv.h.
     52 struct swap_integer_request_10_6 {
     53   mach_msg_header_t Head;
     54   NDR_record_t NDR;
     55   vproc_gsk_t inkey;
     56   vproc_gsk_t outkey;
     57   int64_t inval;
     58 };
     59 
     60 // TODO(rsesek): Libc provides strnlen() starting in 10.7.
     61 size_t strnlen(const char* str, size_t maxlen) {
     62   size_t len = 0;
     63   for (; len < maxlen; ++len, ++str) {
     64     if (*str == '\0')
     65       break;
     66   }
     67   return len;
     68 }
     69 
     70 template <typename R>
     71 std::string LaunchdLookUp2GetRequestName(const mach_msg_header_t* header) {
     72   DCHECK_EQ(sizeof(R), header->msgh_size);
     73   const R* request = reinterpret_cast<const R*>(header);
     74   // Make sure the name is properly NUL-terminated.
     75   const size_t name_length =
     76       strnlen(request->servicename, BOOTSTRAP_MAX_NAME_LEN);
     77   std::string name = std::string(request->servicename, name_length);
     78   return name;
     79 }
     80 
     81 template <typename R>
     82 void LaunchdLookUp2FillReply(mach_msg_header_t* header, mach_port_t port) {
     83   R* reply = reinterpret_cast<R*>(header);
     84   reply->Head.msgh_size = sizeof(R);
     85   reply->Head.msgh_bits =
     86       MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND_ONCE) |
     87       MACH_MSGH_BITS_COMPLEX;
     88   reply->msgh_body.msgh_descriptor_count = 1;
     89   reply->service_port.name = port;
     90   reply->service_port.disposition = MACH_MSG_TYPE_COPY_SEND;
     91   reply->service_port.type = MACH_MSG_PORT_DESCRIPTOR;
     92 }
     93 
     94 template <typename R>
     95 bool LaunchdSwapIntegerIsGetOnly(const mach_msg_header_t* header) {
     96   const R* request = reinterpret_cast<const R*>(header);
     97   return request->inkey == 0 && request->inval == 0 && request->outkey != 0;
     98 }
     99 
    100 }  // namespace
    101 
    102 const LaunchdCompatibilityShim GetLaunchdCompatibilityShim() {
    103   LaunchdCompatibilityShim shim = {
    104     .msg_id_look_up2 = 404,
    105     .msg_id_swap_integer = 416,
    106     .look_up2_fill_reply = &LaunchdLookUp2FillReply<look_up2_reply_10_6>,
    107     .swap_integer_is_get_only =
    108         &LaunchdSwapIntegerIsGetOnly<swap_integer_request_10_6>,
    109   };
    110 
    111   if (base::mac::IsOSSnowLeopard()) {
    112     shim.look_up2_get_request_name =
    113         &LaunchdLookUp2GetRequestName<look_up2_request_10_6>;
    114   } else if (base::mac::IsOSLionOrLater() &&
    115              !base::mac::IsOSYosemiteOrLater()) {
    116     shim.look_up2_get_request_name =
    117         &LaunchdLookUp2GetRequestName<look_up2_request_10_7>;
    118   } else {
    119     DLOG(ERROR) << "Unknown OS, using launchd compatibility shim from 10.7.";
    120     shim.look_up2_get_request_name =
    121         &LaunchdLookUp2GetRequestName<look_up2_request_10_7>;
    122   }
    123 
    124   return shim;
    125 }
    126 
    127 }  // namespace sandbox
    128