2 * Copyright (c) 2018 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 typedef struct _os_mach_port_disposition
{
27 mach_msg_bits_t ompd_bits
;
28 const char *const ompd_human
;
29 } os_mach_port_disposition_t
;
31 #define os_mach_port_disposition_init(d) [d] = { \
36 #pragma mark Top-Level Statics
37 static 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
46 static 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
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
),
60 static inline const char *
61 _mach_port_disposition_string(mach_msg_bits_t d
)
63 if (d
< MACH_MSG_TYPE_MOVE_RECEIVE
) {
66 if (d
> MACH_MSG_TYPE_DISPOSE_SEND_ONCE
) {
69 return _mach_port_dispositions
[d
].ompd_human
;
72 static 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
85 static 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
),
91 static 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
),
100 static 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
),
108 const mach_msg_trailer_t
*
109 os_mach_msg_get_trailer(const mach_msg_header_t
*hdr
)
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
116 return (mach_msg_trailer_t
*)((uint8_t *)hdr
+ round_msg(hdr
->msgh_size
));
119 const mach_msg_audit_trailer_t
*
120 os_mach_msg_get_audit_trailer(const mach_msg_header_t
*hdr
)
122 const mach_msg_trailer_t
*tlr
= NULL
;
123 const mach_msg_audit_trailer_t
*audit_tlr
= NULL
;
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
;
135 const mach_msg_context_trailer_t
*
136 os_mach_msg_get_context_trailer(const mach_msg_header_t
*hdr
)
138 const mach_msg_trailer_t
*tlr
= NULL
;
139 const mach_msg_context_trailer_t
*ctx_tlr
= NULL
;
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
;
152 os_mach_msg_copy_description(const mach_msg_header_t
*msg
)
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
);
163 mach_msg_size_t ool_cnt
= 0;
165 if (msg
->msgh_bits
& MACH_MSGH_BITS_COMPLEX
) {
166 ool_cnt
= ((mach_msg_base_t
*)msg
)->body
.msgh_descriptor_count
;
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
,
180 posix_assert_zero(ret
);
186 os_mach_msg_trailer_copy_description(const mach_msg_trailer_t
*tlr
)
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
;
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
);
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
);
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.
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
);
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
);
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
);
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
);
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
);
266 desc
= os_strdup(buff
);
273 os_mach_port_copy_description(mach_port_t p
)
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
;
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
= "";
289 if (p
== MACH_PORT_NULL
) {
290 return os_strdup("null");
292 if (p
== MACH_PORT_DEAD
) {
293 return os_strdup("dead-name");
296 kr
= mach_port_type(mach_task_self(), p
, &type
);
299 rightdesc
= os_flagset_copy_string(_mach_port_rights
, type
);
300 requestdesc
= os_flagset_copy_string(_mach_port_requests
, type
);
303 ret
= asprintf(&rightdesc
, "[%#x]", kr
);
304 posix_assert_zero(ret
);
307 kr
= mach_port_get_attributes(mach_task_self(), p
,
308 MACH_PORT_RECEIVE_STATUS
, (mach_port_info_t
)&status
, &status_size
);
311 if (status
.mps_flags
) {
312 statusdesc
= os_flagset_copy_string(_mach_port_status
,
315 statusdesc
= os_strdup("[none]");
319 case KERN_INVALID_RIGHT
:
320 if (!(type
& MACH_PORT_TYPE_RECEIVE
)) {
321 statusdesc
= os_strdup("[none]");
325 ret
= asprintf(&statusdesc
, "[%#x]", kr
);
326 posix_assert_zero(ret
);
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";
338 kr
= mach_port_get_refs(mach_task_self(), p
, right
, &urefs
);
341 ret
= asprintf(&urefsdesc
, ", %s urefs = %u", which_urefs
, urefs
);
344 ret
= asprintf(&urefsdesc
, ", %s urefs = [%#x]",
350 ret
= asprintf(&desc
, "name = %#x, rights = %s, requests = %s, "
352 p
, rightdesc
, requestdesc
, statusdesc
, urefsdesc
);
353 posix_assert_zero(ret
);
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.
364 os_assert_mach(const char *op
, kern_return_t kr
)
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
;
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
);
377 if (kr
== KERN_SUCCESS
) {
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";
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]",
390 err_string
= err_buff
;
391 err_type_string
= "unrecognized";
393 err_type_string
= "mach";
396 if (kr
<= MIG_TYPE_ERROR
&& kr
>= MIG_TRAILER_ERROR
) {
397 snprintf(code_buff
, sizeof(code_buff
), "%d", kr
);
399 snprintf(code_buff
, sizeof(code_buff
), "%#x", kr
);
400 special_desc
= os_flagset_copy_string(_mach_special_bits
, extra
);
405 os_crash("%s failed: %s error = %s [%s], special bits = %s",
406 op
, err_type_string
, err_string
, code_buff
, special_desc
);
408 os_crash("%s failed: %s error = %s [%s]",
409 op
, err_type_string
, err_string
, code_buff
);
414 os_assert_mach_port_status(const char *desc
, mach_port_t p
,
415 mach_port_status_t
*expected
)
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
;
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);