summaryrefslogtreecommitdiffstats
path: root/ipc/test_util_mac.cc
blob: 6b6e64bb4afa2eea052d7232d411f5cc9cb27cbb (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
136
137
138
139
140
141
142
143
// Copyright 2015 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 "ipc/test_util_mac.h"

#include <mach/mach_vm.h>
#include <servers/bootstrap.h>
#include <stddef.h>

#include "base/mac/mach_logging.h"
#include "base/mac/scoped_mach_port.h"
#include "base/rand_util.h"
#include "base/strings/stringprintf.h"

namespace {

// Structs used to pass a Mach port over mach_msg().
struct MachSendPortMessage {
  mach_msg_header_t header;
  mach_msg_body_t body;
  mach_msg_port_descriptor_t data;
};

struct MachReceivePortMessage : public MachSendPortMessage {
  mach_msg_trailer_t trailer;
};

}  // namespace

namespace IPC {

std::string CreateRandomServiceName() {
  return base::StringPrintf("TestUtilMac.%llu", base::RandUint64());
}

base::mac::ScopedMachReceiveRight BecomeMachServer(const char* service_name) {
  mach_port_t port;
  kern_return_t kr = bootstrap_check_in(bootstrap_port, service_name, &port);
  MACH_CHECK(kr == KERN_SUCCESS, kr) << "BecomeMachServer ";
  return base::mac::ScopedMachReceiveRight(port);
}

base::mac::ScopedMachSendRight LookupServer(const char* service_name) {
  mach_port_t server_port;
  kern_return_t kr =
      bootstrap_look_up(bootstrap_port, service_name, &server_port);
  MACH_CHECK(kr == KERN_SUCCESS, kr) << "LookupServer";
  return base::mac::ScopedMachSendRight(server_port);
}

base::mac::ScopedMachReceiveRight MakeReceivingPort() {
  mach_port_t client_port;
  kern_return_t kr = mach_port_allocate(mach_task_self(),
                                        MACH_PORT_RIGHT_RECEIVE, &client_port);
  MACH_CHECK(kr == KERN_SUCCESS, kr) << "MakeReceivingPort";
  return base::mac::ScopedMachReceiveRight(client_port);
}

base::mac::ScopedMachSendRight ReceiveMachPort(mach_port_t port_to_listen_on) {
  MachReceivePortMessage recv_msg;
  mach_msg_header_t* recv_hdr = &recv_msg.header;
  recv_hdr->msgh_local_port = port_to_listen_on;
  recv_hdr->msgh_size = sizeof(recv_msg);
  kern_return_t kr =
      mach_msg(recv_hdr, MACH_RCV_MSG, 0, recv_hdr->msgh_size,
               port_to_listen_on, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
  MACH_CHECK(kr == KERN_SUCCESS, kr) << "ReceiveMachPort";
  mach_port_t other_task_port = recv_msg.data.name;
  return base::mac::ScopedMachSendRight(other_task_port);
}

// Passes a copy of the send right of |port_to_send| to |receiving_port|.
void SendMachPort(mach_port_t receiving_port,
                  mach_port_t port_to_send,
                  int disposition) {
  MachSendPortMessage send_msg;
  send_msg.header.msgh_bits =
      MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX;
  send_msg.header.msgh_size = sizeof(send_msg);
  send_msg.header.msgh_remote_port = receiving_port;
  send_msg.header.msgh_local_port = MACH_PORT_NULL;
  send_msg.header.msgh_reserved = 0;
  send_msg.header.msgh_id = 0;
  send_msg.body.msgh_descriptor_count = 1;
  send_msg.data.name = port_to_send;
  send_msg.data.disposition = disposition;
  send_msg.data.type = MACH_MSG_PORT_DESCRIPTOR;
  int kr = mach_msg(&send_msg.header, MACH_SEND_MSG, send_msg.header.msgh_size,
                    0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
  MACH_CHECK(kr == KERN_SUCCESS, kr) << "SendMachPort";
}

mach_msg_type_number_t GetActiveNameCount() {
  mach_port_name_array_t name_array;
  mach_msg_type_number_t names_count;
  mach_port_type_array_t type_array;
  mach_msg_type_number_t types_count;
  kern_return_t kr = mach_port_names(mach_task_self(), &name_array,
                                     &names_count, &type_array, &types_count);
  MACH_CHECK(kr == KERN_SUCCESS, kr) << "GetActiveNameCount";
  return names_count;
}

mach_port_urefs_t GetMachRefCount(mach_port_name_t name,
                                  mach_port_right_t right) {
  mach_port_urefs_t ref_count;
  kern_return_t kr = mach_port_get_refs(mach_task_self(), name,
                                        MACH_PORT_RIGHT_SEND, &ref_count);
  MACH_CHECK(kr == KERN_SUCCESS, kr) << "GetRefCount";
  return ref_count;
}

void IncrementMachRefCount(mach_port_name_t name, mach_port_right_t right) {
  kern_return_t kr = mach_port_mod_refs(mach_task_self(), name, right, 1);
  MACH_CHECK(kr == KERN_SUCCESS, kr) << "GetRefCount";
}

bool GetMachProtections(void* address, size_t size, int* current, int* max) {
  vm_region_info_t region_info;
  mach_vm_address_t mem_address = reinterpret_cast<mach_vm_address_t>(address);
  mach_vm_size_t mem_size = size;
  vm_region_basic_info_64 basic_info;

  region_info = reinterpret_cast<vm_region_recurse_info_t>(&basic_info);
  vm_region_flavor_t flavor = VM_REGION_BASIC_INFO_64;
  memory_object_name_t memory_object;
  mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;

  kern_return_t kr =
      mach_vm_region(mach_task_self(), &mem_address, &mem_size, flavor,
                     region_info, &count, &memory_object);
  if (kr != KERN_SUCCESS) {
    MACH_LOG(ERROR, kr) << "Failed to get region info.";
    return false;
  }

  *current = basic_info.protection;
  *max = basic_info.max_protection;
  return true;
}

}  // namespace IPC