xref: /xnu-12377.61.12/tests/ipc/ipc_utils.c (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
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