]> git.saurik.com Git - apple/libc.git/blame - libdarwin/mach.c
Libc-1353.41.1.tar.gz
[apple/libc.git] / libdarwin / mach.c
CommitLineData
70ad1dc8
A
1/*
2 * Copyright (c) 2018 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23#include "internal.h"
24
25#pragma mark Types
26typedef struct _os_mach_port_disposition {
27 mach_msg_bits_t ompd_bits;
28 const char *const ompd_human;
29} os_mach_port_disposition_t;
30
31#define os_mach_port_disposition_init(d) [d] = { \
32 .ompd_bits = (d), \
33 .ompd_human = #d, \
34}
35
36#pragma mark Top-Level Statics
37static const os_flagset_t _mach_msgh_bits = {
38 os_flag_init(MACH_MSGH_BITS_COMPLEX),
39 os_flag_init(MACH_MSGH_BITS_RAISEIMP),
40 // MACH_MSGH_BITS_DENAP is deprecated
41 os_flag_init(MACH_MSGH_BITS_IMPHOLDASRT),
42 // MACH_MSGH_BITS_DENAPHOLDASRT is deprecated
43 // MACH_MSGH_BITS_CIRCULAR is kernel-internal
44};
45
46static const os_mach_port_disposition_t _mach_port_dispositions[] = {
47 os_mach_port_disposition_init(MACH_MSG_TYPE_MOVE_RECEIVE),
48 os_mach_port_disposition_init(MACH_MSG_TYPE_MOVE_SEND),
49 os_mach_port_disposition_init(MACH_MSG_TYPE_MOVE_SEND_ONCE),
50 os_mach_port_disposition_init(MACH_MSG_TYPE_COPY_SEND),
51 os_mach_port_disposition_init(MACH_MSG_TYPE_MAKE_SEND),
52 os_mach_port_disposition_init(MACH_MSG_TYPE_MAKE_SEND_ONCE),
53 // MACH_MSG_TYPE_COPY_RECEIVE is not a valid operation, so unclear why it's
54 // even defined
55 os_mach_port_disposition_init(MACH_MSG_TYPE_DISPOSE_RECEIVE),
56 os_mach_port_disposition_init(MACH_MSG_TYPE_DISPOSE_SEND),
57 os_mach_port_disposition_init(MACH_MSG_TYPE_DISPOSE_SEND_ONCE),
58};
59
60static inline const char *
61_mach_port_disposition_string(mach_msg_bits_t d)
62{
63 if (d < MACH_MSG_TYPE_MOVE_RECEIVE) {
64 return "[invalid]";
65 }
66 if (d > MACH_MSG_TYPE_DISPOSE_SEND_ONCE) {
67 return "[invalid]";
68 }
69 return _mach_port_dispositions[d].ompd_human;
70}
71
72static const os_flagset_t _mach_port_rights = {
73 os_flag_init(MACH_PORT_TYPE_SEND),
74 os_flag_init(MACH_PORT_TYPE_RECEIVE),
75 os_flag_init(MACH_PORT_TYPE_SEND_ONCE),
76 os_flag_init(MACH_PORT_TYPE_PORT_SET),
77 os_flag_init(MACH_PORT_TYPE_DEAD_NAME),
78 // MACH_PORT_TYPE_LABELH is obsolete
79 // MACH_PORT_TYPE_DNREQUEST->_mach_port_requests
80 // MACH_PORT_TYPE_SPREQUEST->_mach_port_requests
81 // MACH_PORT_TYPE_SPREQUEST_DELAYED->_mach_port_requests
82 // MACH_PORT_RIGHT_NUMBER is obsolete
83};
84
85static const os_flagset_t _mach_port_requests = {
86 os_flag_init(MACH_PORT_TYPE_DNREQUEST),
87 os_flag_init(MACH_PORT_TYPE_SPREQUEST),
88 os_flag_init(MACH_PORT_TYPE_SPREQUEST_DELAYED),
89};
90
91static const os_flagset_t _mach_port_status = {
92 os_flag_init(MACH_PORT_STATUS_FLAG_TEMPOWNER),
93 os_flag_init(MACH_PORT_STATUS_FLAG_GUARDED),
94 os_flag_init(MACH_PORT_STATUS_FLAG_STRICT_GUARD),
95 os_flag_init(MACH_PORT_STATUS_FLAG_IMP_DONATION),
96 // MACH_PORT_STATUS_FLAG_REVIVE is obsolete
97 os_flag_init(MACH_PORT_STATUS_FLAG_TASKPTR),
98};
99
100static const os_flagset_t _mach_special_bits = {
101 os_flag_init(MACH_MSG_IPC_SPACE),
102 os_flag_init(MACH_MSG_VM_SPACE),
103 os_flag_init(MACH_MSG_IPC_KERNEL),
104 os_flag_init(MACH_MSG_VM_KERNEL),
105};
106
107#pragma mark API
108const mach_msg_trailer_t *
109os_mach_msg_get_trailer(const mach_msg_header_t *hdr)
110{
111 // The mach_msg() documentation states that the trailer will follow the
112 // message body on the next natural boundary. But when we moved to 64-bit,
113 // we kept the trailer alignment on a 4-byte boundary for compatibility
114 // reasons. Specifically, natural_t is still 32 bits on both 32- and 64-bit
115 // platforms.
116 return (mach_msg_trailer_t *)((uint8_t *)hdr + round_msg(hdr->msgh_size));
117}
118
119const mach_msg_audit_trailer_t *
120os_mach_msg_get_audit_trailer(const mach_msg_header_t *hdr)
121{
122 const mach_msg_trailer_t *tlr = NULL;
123 const mach_msg_audit_trailer_t *audit_tlr = NULL;
124
125 tlr = os_mach_msg_get_trailer(hdr);
126 if (tlr->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0) {
127 if (tlr->msgh_trailer_size >= sizeof(mach_msg_audit_trailer_t)) {
128 audit_tlr = (mach_msg_audit_trailer_t *)tlr;
129 }
130 }
131
132 return audit_tlr;
133}
134
135const mach_msg_context_trailer_t *
136os_mach_msg_get_context_trailer(const mach_msg_header_t *hdr)
137{
138 const mach_msg_trailer_t *tlr = NULL;
139 const mach_msg_context_trailer_t *ctx_tlr = NULL;
140
141 tlr = os_mach_msg_get_trailer(hdr);
142 if (tlr->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0) {
143 if (tlr->msgh_trailer_size >= sizeof(mach_msg_context_trailer_t)) {
144 ctx_tlr = (mach_msg_context_trailer_t *)tlr;
145 }
146 }
147
148 return ctx_tlr;
149}
150
151char *
152os_mach_msg_copy_description(const mach_msg_header_t *msg)
153{
154 int ret = -1;
155 mach_msg_bits_t local = MACH_MSGH_BITS_LOCAL(msg->msgh_bits);
156 mach_msg_bits_t remote = MACH_MSGH_BITS_REMOTE(msg->msgh_bits);
157 mach_msg_bits_t voucher = MACH_MSGH_BITS_VOUCHER(msg->msgh_bits);
158 char *__os_free bits_desc = NULL;
159 const char *local_desc = _mach_port_disposition_string(local);
160 const char *remote_desc = _mach_port_disposition_string(remote);
161 const char *voucher_desc = _mach_port_disposition_string(voucher);
162 char *desc = NULL;
163 mach_msg_size_t ool_cnt = 0;
164
165 if (msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
166 ool_cnt = ((mach_msg_base_t *)msg)->body.msgh_descriptor_count;
167 }
168
169 bits_desc = os_flagset_copy_string(_mach_msgh_bits, msg->msgh_bits);
170 ret = asprintf(&desc, "id = %#x, size = %u, bits = %s, "
171 "local disp = %s, local port = %#x, "
172 "remote disp = %s, remote port = %#x, "
173 "voucher disp = %s, voucher port = %#x, "
174 "out-of-line descriptor cnt = %u",
175 msg->msgh_id, msg->msgh_size, bits_desc,
176 local_desc, msg->msgh_local_port,
177 remote_desc, msg->msgh_remote_port,
178 voucher_desc, msg->msgh_voucher_port,
179 ool_cnt);
180 posix_assert_zero(ret);
181
182 return desc;
183}
184
185char *
186os_mach_msg_trailer_copy_description(const mach_msg_trailer_t *tlr)
187{
188 union {
189 int r;
190 size_t n;
191 } ret = {
192 .r = -1,
193 };
194 char *desc = NULL;
195 char buff[512];
196 char *cursor = buff;
197 size_t left = sizeof(buff);
198 // Yes we do not know the actual size of the trailer yet, so this is
199 // technically unsafe, but we only dereference members after determining
200 // that they are safe to dereference. Just us chickens and all that.
201 const mach_msg_mac_trailer_t *max = (const mach_msg_mac_trailer_t *)tlr;
202
203 if (tlr->msgh_trailer_type != MACH_MSG_TRAILER_FORMAT_0) {
204 ret.r = asprintf(&desc, "type = %u, size = %u",
205 tlr->msgh_trailer_type, tlr->msgh_trailer_size);
206 os_assert_zero(ret.r);
207 goto __out;
208 }
209
210 if (tlr->msgh_trailer_size >= sizeof(mach_msg_trailer_t)) {
211 ret.r = snprintf(cursor, left, "format = %u, size = %u",
212 tlr->msgh_trailer_type, tlr->msgh_trailer_size);
213 os_assert_sprintf(ret.r, left);
214
215 // Safe since the above assert has verified that ret is both positive
216 // and less than or equal to the size of the buffer.
217 cursor += ret.n;
218 left -= ret.n;
219 }
220
221 if (tlr->msgh_trailer_size >= sizeof(mach_msg_seqno_trailer_t)) {
222 ret.r = snprintf(cursor, left, ", seqno = %u", max->msgh_seqno);
223 os_assert_sprintf(ret.r, left);
224 cursor += ret.n;
225 left -= ret.n;
226 }
227
228 if (tlr->msgh_trailer_size >= sizeof(mach_msg_security_trailer_t)) {
229 ret.r = snprintf(cursor, left, ", security.uid = %u, security.gid = %u",
230 max->msgh_sender.val[0], max->msgh_sender.val[1]);
231 os_assert_sprintf(ret.r, left);
232 cursor += ret.n;
233 left -= ret.n;
234 }
235
236 if (tlr->msgh_trailer_size >= sizeof(mach_msg_audit_trailer_t)) {
237 ret.r = snprintf(cursor, left, ", audit.auid = %u, "
238 "audit.euid = %u, audit.egid = %u, "
239 "audit.ruid = %u, audit.rgid = %u, "
240 "audit.pid = %u, audit.asid = %u, audit.pidvers = %u",
241 max->msgh_audit.val[0], max->msgh_audit.val[1],
242 max->msgh_audit.val[2], max->msgh_audit.val[3],
243 max->msgh_audit.val[4], max->msgh_audit.val[5],
244 max->msgh_audit.val[6], max->msgh_audit.val[7]);
245 os_assert_sprintf(ret.r, left);
246 cursor += ret.n;
247 left -= ret.n;
248 }
249
250 if (tlr->msgh_trailer_size >= sizeof(mach_msg_context_trailer_t)) {
251 uint64_t ctx = max->msgh_context;
252 ret.r = snprintf(cursor, left, ", context = %#llx", ctx);
253 os_assert_sprintf(ret.r, left);
254 cursor += ret.n;
255 left -= ret.n;
256 }
257
258 if (tlr->msgh_trailer_size >= sizeof(mach_msg_mac_trailer_t)) {
259 ret.r = snprintf(cursor, left, ", labels.sender = %#x",
260 max->msgh_labels.sender);
261 os_assert_sprintf(ret.r, left);
262 cursor += ret.n;
263 left -= ret.n;
264 }
265
266 desc = os_strdup(buff);
267
268__out:
269 return desc;
270}
271
272char *
273os_mach_port_copy_description(mach_port_t p)
274{
275 kern_return_t kr = KERN_FAILURE;
276 mach_port_right_t right = 0;
277 mach_port_type_t type = 0;
278 mach_port_urefs_t urefs = 0;
279 mach_port_status_t status;
280 mach_msg_type_number_t status_size = MACH_PORT_RECEIVE_STATUS_COUNT;
281 char *desc = NULL;
282 char *__os_free rightdesc = NULL;
283 char *__os_free requestdesc = NULL;
284 char *__os_free statusdesc = NULL;
285 char *__os_free urefsdesc = NULL;
286 char *which_urefs = "";
287 int ret = -1;
288
289 if (p == MACH_PORT_NULL) {
290 return os_strdup("null");
291 }
292 if (p == MACH_PORT_DEAD) {
293 return os_strdup("dead-name");
294 }
295
296 kr = mach_port_type(mach_task_self(), p, &type);
297 switch (kr) {
298 case KERN_SUCCESS:
299 rightdesc = os_flagset_copy_string(_mach_port_rights, type);
300 requestdesc = os_flagset_copy_string(_mach_port_requests, type);
301 break;
302 default:
303 ret = asprintf(&rightdesc, "[%#x]", kr);
304 posix_assert_zero(ret);
305 }
306
307 kr = mach_port_get_attributes(mach_task_self(), p,
308 MACH_PORT_RECEIVE_STATUS, (mach_port_info_t)&status, &status_size);
309 switch (kr) {
310 case KERN_SUCCESS:
311 if (status.mps_flags) {
312 statusdesc = os_flagset_copy_string(_mach_port_status,
313 status.mps_flags);
314 } else {
315 statusdesc = os_strdup("[none]");
316 }
317
318 break;
319 case KERN_INVALID_RIGHT:
320 if (!(type & MACH_PORT_TYPE_RECEIVE)) {
321 statusdesc = os_strdup("[none]");
322 break;
323 }
324 default:
325 ret = asprintf(&statusdesc, "[%#x]", kr);
326 posix_assert_zero(ret);
327 }
328
329 if (type & MACH_PORT_TYPE_SEND) {
330 right = MACH_PORT_RIGHT_SEND;
331 which_urefs = "send";
332 } else if (type & MACH_PORT_TYPE_DEAD_NAME) {
333 right = MACH_PORT_RIGHT_DEAD_NAME;
334 which_urefs = "dead name";
335 }
336
337 if (which_urefs) {
338 kr = mach_port_get_refs(mach_task_self(), p, right, &urefs);
339 switch (kr) {
340 case KERN_SUCCESS:
341 ret = asprintf(&urefsdesc, ", %s urefs = %u", which_urefs, urefs);
342 break;
343 default:
344 ret = asprintf(&urefsdesc, ", %s urefs = [%#x]",
345 which_urefs, kr);
346 break;
347 }
348 }
349
350 ret = asprintf(&desc, "name = %#x, rights = %s, requests = %s, "
351 "status = %s%s",
352 p, rightdesc, requestdesc, statusdesc, urefsdesc);
353 posix_assert_zero(ret);
354
355 return desc;
356}
357
358#pragma mark API from <os/assumes.h>
359// These live here because the implementations uses functionality from
360// libdarwin, and we don't want to have a circular dependency between Libc and
361// libsystem_darwin. The long-term plan is to move assumes() and assert()
362// functionality into libdarwin anyway.
363void
507116e3 364(os_assert_mach)(const char *op, kern_return_t kr)
70ad1dc8
A
365{
366 kern_return_t real_kr = (kern_return_t)(kr & (~MACH_MSG_MASK));
367 kern_return_t extra = (kern_return_t)(kr & MACH_MSG_MASK);
368 const char *err_string = NULL;
369 const char *err_type_string = NULL;
370 char err_buff[64];
371 char code_buff[16];
372 const char *special_desc = NULL;
373 int sys = err_get_system(real_kr);
374 int sub = err_get_sub(real_kr);
375 int code = err_get_code(real_kr);
376
377 if (kr == KERN_SUCCESS) {
378 return;
379 }
380
381 if (kr >= BOOTSTRAP_NOT_PRIVILEGED && kr <= BOOTSTRAP_NO_CHILDREN) {
382 err_string = bootstrap_strerror(kr);
383 snprintf(code_buff, sizeof(code_buff), "%d", kr);
384 err_type_string = "bootstrap";
385 } else {
386 err_string = mach_error_string(real_kr);
387 if (strcmp(err_string, "unknown error code") == 0) {
388 snprintf(err_buff, sizeof(err_buff), "[%#x|%#x|%#x]",
389 sys, sub, code);
390 err_string = err_buff;
391 err_type_string = "unrecognized";
392 } else {
393 err_type_string = "mach";
394 }
395
396 if (kr <= MIG_TYPE_ERROR && kr >= MIG_TRAILER_ERROR) {
397 snprintf(code_buff, sizeof(code_buff), "%d", kr);
398 } else {
399 snprintf(code_buff, sizeof(code_buff), "%#x", kr);
400 special_desc = os_flagset_copy_string(_mach_special_bits, extra);
401 }
402 }
403
404 if (special_desc) {
405 os_crash("%s failed: %s error = %s [%s], special bits = %s",
406 op, err_type_string, err_string, code_buff, special_desc);
407 } else {
408 os_crash("%s failed: %s error = %s [%s]",
409 op, err_type_string, err_string, code_buff);
410 }
411}
412
413void
414os_assert_mach_port_status(const char *desc, mach_port_t p,
415 mach_port_status_t *expected)
416{
417 kern_return_t kr = KERN_FAILURE;
418 mach_port_status_t status;
419 mach_msg_type_number_t status_cnt = MACH_PORT_RECEIVE_STATUS_COUNT;
420
421 kr = mach_port_get_attributes(mach_task_self(), p, MACH_PORT_RECEIVE_STATUS,
422 (mach_port_info_t)&status, &status_cnt);
423 os_assert_mach("get status", kr);
424
425 if (expected->mps_pset != UINT32_MAX) {
426 if (expected->mps_pset != status.mps_pset) {
427 os_crash("port set mismatch: actual = %u, expected = %u",
428 status.mps_pset, expected->mps_pset);
429 }
430 }
431 if (expected->mps_seqno != UINT32_MAX) {
432 if (expected->mps_seqno != status.mps_seqno) {
433 os_crash("sequence number mismatch: actual = %u, expected = %u",
434 status.mps_seqno, expected->mps_seqno);
435 }
436 }
437 if (expected->mps_mscount != UINT32_MAX) {
438 if (expected->mps_mscount != status.mps_mscount) {
439 os_crash("make-send count mismatch: actual = %u, expected = %u",
440 status.mps_mscount, expected->mps_mscount);
441 }
442 }
443 if (expected->mps_qlimit != UINT32_MAX) {
444 if (expected->mps_qlimit != status.mps_qlimit) {
445 os_crash("queue limit mismatch: actual = %u, expected = %u",
446 status.mps_qlimit, expected->mps_qlimit);
447 }
448 }
449 if (expected->mps_msgcount != UINT32_MAX) {
450 if (expected->mps_msgcount != status.mps_msgcount) {
451 os_crash("message count mismatch: actual = %u, expected = %u",
452 status.mps_msgcount, expected->mps_msgcount);
453 }
454 }
455 if (expected->mps_sorights != UINT32_MAX) {
456 if (expected->mps_sorights != status.mps_sorights) {
457 os_crash("send-once rights mismatch: actual = %u, expected = %u",
458 status.mps_sorights, expected->mps_sorights);
459 }
460 }
461 if (expected->mps_srights != INT32_MAX) {
462 if (expected->mps_srights != status.mps_srights) {
463 os_crash("send rights mismatch: actual = %d, expected = %d",
464 status.mps_srights, expected->mps_srights);
465 }
466 }
467 if (expected->mps_pdrequest != INT32_MAX) {
468 if (expected->mps_pdrequest != status.mps_pdrequest) {
469 os_crash("port-destroyed mismatch: actual = %d, expected = %d",
470 status.mps_pdrequest, expected->mps_pdrequest);
471 }
472 }
473 if (expected->mps_nsrequest != INT32_MAX) {
474 if (expected->mps_nsrequest != status.mps_nsrequest) {
475 os_crash("no-senders mismatch: actual = %d, expected = %d",
476 status.mps_nsrequest, expected->mps_nsrequest);
477 }
478 }
479 if (expected->mps_flags) {
480 if (expected->mps_flags != status.mps_flags) {
481 os_crash("flags mismatch: actual = %#x, expected = %#x",
482 status.mps_flags, expected->mps_flags);
483 }
484 }
485}