summaryrefslogtreecommitdiffstats
path: root/sandbox/mac/os_compatibility.cc
blob: 6624f3a19be760740d8e1840287868e094b2a181 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// 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 <servers/bootstrap.h>
#include <unistd.h>

#include "base/mac/mac_util.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;
}

uint64_t MachGetMessageID(const IPCMessage message) {
  return message.mach->msgh_id;
}

template <typename R>
std::string LaunchdLookUp2GetRequestName(const IPCMessage message) {
  mach_msg_header_t* header = message.mach;
  DCHECK_EQ(sizeof(R), header->msgh_size);
  const R* request = reinterpret_cast<const R*>(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;
}

template <typename R>
void LaunchdLookUp2FillReply(IPCMessage message, mach_port_t port) {
  R* reply = reinterpret_cast<R*>(message.mach);
  reply->Head.msgh_size = sizeof(R);
  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 = port;
  reply->service_port.disposition = MACH_MSG_TYPE_COPY_SEND;
  reply->service_port.type = MACH_MSG_PORT_DESCRIPTOR;
}

template <typename R>
bool LaunchdSwapIntegerIsGetOnly(const IPCMessage message) {
  const R* request = reinterpret_cast<const R*>(message.mach);
  return request->inkey == 0 && request->inval == 0 && request->outkey != 0;
}

}  // namespace

const LaunchdCompatibilityShim GetLaunchdCompatibilityShim() {
  LaunchdCompatibilityShim shim = {
    .ipc_message_get_id = &MachGetMessageID,
    .msg_id_look_up2 = 404,
    .msg_id_swap_integer = 416,
    .look_up2_fill_reply = &LaunchdLookUp2FillReply<look_up2_reply_10_6>,
    .swap_integer_is_get_only =
        &LaunchdSwapIntegerIsGetOnly<swap_integer_request_10_6>,
  };

  if (base::mac::IsOSSnowLeopard()) {
    shim.look_up2_get_request_name =
        &LaunchdLookUp2GetRequestName<look_up2_request_10_6>;
  } else if (base::mac::IsOSLionOrLater() &&
             !base::mac::IsOSYosemiteOrLater()) {
    shim.look_up2_get_request_name =
        &LaunchdLookUp2GetRequestName<look_up2_request_10_7>;
  } else {
    DLOG(ERROR) << "Unknown OS, using launchd compatibility shim from 10.7.";
    shim.look_up2_get_request_name =
        &LaunchdLookUp2GetRequestName<look_up2_request_10_7>;
  }

  return shim;
}

}  // namespace sandbox