1 #include "ipc_utils.h"
2 #include <darwintest.h>
3 #include <unistd.h>
4 #include <sys/types.h>
5 #include <sys/sysctl.h>
6
7 /*
8 * Implementation of common IPC utilities for XNU tests
9 *
10 * Note: This implementation is designed specifically for test environments
11 * and uses darwintest T_QUIET macros for internal validations.
12 */
13
14 /*
15 * Port Management Functions
16 */
17
18 mach_port_t
ipc_create_receive_port(void)19 ipc_create_receive_port(void)
20 {
21 return ipc_create_receive_port_with_options(0);
22 }
23
24 mach_port_t
ipc_create_receive_port_with_options(uint32_t mpo_flags)25 ipc_create_receive_port_with_options(uint32_t mpo_flags)
26 {
27 mach_port_options_t opts = {
28 .flags = mpo_flags,
29 };
30 mach_port_name_t port;
31 kern_return_t kr;
32
33 kr = mach_port_construct(mach_task_self(), &opts, 0, &port);
34 T_ASSERT_MACH_SUCCESS(kr, "ipc_create_receive_port_with_options");
35
36 return port;
37 }
38
39 void
ipc_deallocate_port(mach_port_t port)40 ipc_deallocate_port(mach_port_t port)
41 {
42 if (port != MACH_PORT_NULL) {
43 kern_return_t kr = mach_port_deallocate(mach_task_self(), port);
44 T_ASSERT_MACH_SUCCESS(kr, "ipc_deallocate_port");
45 }
46 }
47
48 kern_return_t
ipc_insert_send_right(mach_port_t receive_port)49 ipc_insert_send_right(mach_port_t receive_port)
50 {
51 kern_return_t kr = mach_port_insert_right(mach_task_self(), receive_port,
52 receive_port, MACH_MSG_TYPE_MAKE_SEND);
53 T_ASSERT_MACH_SUCCESS(kr, "ipc_insert_send_right");
54 return kr;
55 }
56
57 /*
58 * Single Port Messaging Functions
59 */
60
61 kern_return_t
ipc_send_port(mach_port_t destination,mach_port_t port,mach_msg_type_name_t disposition)62 ipc_send_port(mach_port_t destination, mach_port_t port, mach_msg_type_name_t disposition)
63 {
64 ipc_single_port_msg_t msg = {
65 .header = {
66 .msgh_remote_port = destination,
67 .msgh_local_port = MACH_PORT_NULL,
68 .msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX,
69 .msgh_size = sizeof(ipc_single_port_msg_t),
70 .msgh_id = 0x1001 /* Single port message ID */
71 },
72 .body = {
73 .msgh_descriptor_count = 1
74 },
75 .port = {
76 .name = port,
77 .disposition = disposition,
78 .type = MACH_MSG_PORT_DESCRIPTOR
79 }
80 };
81
82 return ipc_send_message(&msg.header);
83 }
84
85 kern_return_t
ipc_receive_port(mach_port_t destination,mach_port_t * port)86 ipc_receive_port(mach_port_t destination, mach_port_t *port)
87 {
88 ipc_receive_msg_t msg;
89 kern_return_t kr;
90
91 kr = ipc_receive_message(destination, &msg, sizeof(ipc_receive_msg_t));
92 if (kr == KERN_SUCCESS) {
93 if (msg.header.msgh_id == 0x1001 && msg.body.msgh_descriptor_count == 1) {
94 *port = msg.data.single.port.name;
95 } else {
96 kr = KERN_INVALID_ARGUMENT;
97 }
98 }
99
100 return kr;
101 }
102
103
104 /*
105 * Port Array Messaging Functions
106 */
107
108 kern_return_t
ipc_send_port_array(mach_port_t destination,mach_port_t * ports,mach_msg_type_number_t count,mach_msg_type_name_t disposition)109 ipc_send_port_array(mach_port_t destination,
110 mach_port_t *ports, mach_msg_type_number_t count,
111 mach_msg_type_name_t disposition)
112 {
113 ipc_port_array_msg_t msg = {
114 .header = {
115 .msgh_remote_port = destination,
116 .msgh_local_port = MACH_PORT_NULL,
117 .msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX,
118 .msgh_size = sizeof(ipc_port_array_msg_t),
119 .msgh_id = 0x1004 /* Port array message ID */
120 },
121 .body = {
122 .msgh_descriptor_count = 1
123 },
124 .ports_descriptor = {
125 .address = (void*)ports,
126 .count = count,
127 .deallocate = FALSE,
128 .disposition = disposition,
129 .type = MACH_MSG_OOL_PORTS_DESCRIPTOR
130 }
131 };
132
133 return ipc_send_message(&msg.header);
134 }
135
136 kern_return_t
ipc_receive_port_array(mach_port_t destination,mach_port_t ** ports,mach_msg_type_number_t * count)137 ipc_receive_port_array(mach_port_t destination,
138 mach_port_t **ports, mach_msg_type_number_t *count)
139 {
140 ipc_receive_msg_t msg;
141 kern_return_t kr;
142
143 kr = ipc_receive_message(destination, &msg, sizeof(ipc_receive_msg_t));
144 if (kr == KERN_SUCCESS) {
145 if (msg.header.msgh_id == 0x1004 && msg.body.msgh_descriptor_count == 1) {
146 *ports = (mach_port_t*)msg.data.array.ports_descriptor.address;
147 *count = msg.data.array.ports_descriptor.count;
148 } else {
149 kr = KERN_INVALID_ARGUMENT;
150 }
151 }
152
153 return kr;
154 }
155
156 /*
157 * Generic Messaging Functions
158 */
159
160 kern_return_t
ipc_send_message(mach_msg_header_t * msg)161 ipc_send_message(mach_msg_header_t *msg)
162 {
163 kern_return_t kr = mach_msg(msg, MACH_SEND_MSG, msg->msgh_size, 0,
164 MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
165 return kr;
166 }
167
168 kern_return_t
ipc_receive_message(mach_port_t destination,ipc_receive_msg_t * msg,mach_msg_size_t max_size)169 ipc_receive_message(mach_port_t destination, ipc_receive_msg_t *msg, mach_msg_size_t max_size)
170 {
171 kern_return_t kr = mach_msg(&msg->header, MACH_RCV_MSG, 0, max_size,
172 destination, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
173 return kr;
174 }
175
176
177 /*
178 * Security and Code Signing Utilities
179 */
180
181 bool
ipc_hardening_disabled(void)182 ipc_hardening_disabled(void)
183 {
184 #if TARGET_OS_OSX || TARGET_OS_BRIDGE
185 /*
186 * CS_CONFIG_GET_OUT_OF_MY_WAY (enabled via AMFI boot-args)
187 * disables IPC security features. Unfortunately,
188 * BATS runs with this boot-arg enabled very frequently.
189 */
190 code_signing_config_t cur_cs_config = 0;
191 size_t cs_config_size = sizeof(cur_cs_config);
192 int result = sysctlbyname("security.codesigning.config", &cur_cs_config,
193 &cs_config_size, NULL, 0);
194 if (result != 0) {
195 T_QUIET; T_LOG("ipc_hardening_disabled: failed to get codesigning config, assuming not disabled");
196 return false;
197 }
198 return (cur_cs_config & CS_CONFIG_GET_OUT_OF_MY_WAY) != 0;
199 #else /* TARGET_OS_OSX || TARGET_OS_BRIDGE */
200 /* mach hardening is only disabled by boot-args on macOS */
201 return false;
202 #endif
203 }
204