1 #define T_NAMESPACE "xnu.ipc"
2 #include <darwintest.h>
10 #include <pthread/qos_private.h>
11 #include <voucher/ipc_pthread_priority_types.h>
13 T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
21 ReplyWithReplyPortMove
,
22 ReplyWithReplyPortCplxBit
,
23 ReplyWithReplyPortMoveCplxBit
,
27 ReplyWithVoucherGarbage
30 struct exc_thread_arg
{
36 reply_type_str(ReplyType rt
)
39 case ReplyWithNoError
:
40 return "ReplyWithNoError";
41 case ReplyWithReplyPort
:
42 return "ReplyWithReplyPort";
43 case ReplyWithReplyPortMove
:
44 return "ReplyWithReplyPortMove";
45 case ReplyWithReplyPortCplxBit
:
46 return "ReplyWithReplyPortCplxBit";
47 case ReplyWithReplyPortMoveCplxBit
:
48 return "ReplyWithReplyPortMoveCplxBit";
49 case ReplyWithPortDesc
:
50 return "ReplyWithPortDesc";
51 case ReplyWithOOLDesc
:
52 return "ReplyWithOOLDesc";
53 case ReplyWithVoucher
:
54 return "ReplyWithVoucher";
55 case ReplyWithVoucherGarbage
:
56 return "ReplyWithVoucherGarbage";
61 create_pthpriority_voucher(void)
63 char voucher_buf
[sizeof(mach_voucher_attr_recipe_data_t
) + sizeof(ipc_pthread_priority_value_t
)];
65 mach_voucher_t voucher
= MACH_PORT_NULL
;
67 ipc_pthread_priority_value_t ipc_pthread_priority_value
=
68 (ipc_pthread_priority_value_t
)_pthread_qos_class_encode(QOS_CLASS_USER_INTERACTIVE
, 0, 0);
70 mach_voucher_attr_raw_recipe_size_t recipe_size
= 0;
71 mach_voucher_attr_recipe_t recipe
=
72 (mach_voucher_attr_recipe_t
)&voucher_buf
[0];
74 recipe
->key
= MACH_VOUCHER_ATTR_KEY_PTHPRIORITY
;
75 recipe
->command
= MACH_VOUCHER_ATTR_PTHPRIORITY_CREATE
;
76 recipe
->previous_voucher
= MACH_VOUCHER_NULL
;
78 memcpy((char *)&recipe
->content
[0], &ipc_pthread_priority_value
, sizeof(ipc_pthread_priority_value
));
79 recipe
->content_size
= sizeof(ipc_pthread_priority_value_t
);
80 recipe_size
+= sizeof(mach_voucher_attr_recipe_data_t
) + recipe
->content_size
;
82 kr
= host_create_mach_voucher(mach_host_self(),
83 (mach_voucher_attr_raw_recipe_array_t
)&voucher_buf
[0],
87 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "host_create_mach_voucher");
92 handle_exceptions(void *arg
)
94 struct exc_thread_arg
*ta
= (struct exc_thread_arg
*)arg
;
95 mach_port_t ePort
= ta
->port
;
96 ReplyType reply_type
= ta
->rt
;
98 char msg_store
[MSG
+ MAX_TRAILER_SIZE
];
99 char reply_store
[MSG
];
100 mach_msg_header_t
*msg
= (mach_msg_header_t
*)msg_store
;
104 kr
= vm_allocate(mach_task_self(), &page
, PG_ALLOC
, VM_FLAGS_ANYWHERE
);
105 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "ool page allocation of %d bytes", PG_ALLOC
);
107 mach_voucher_t voucher
= create_pthpriority_voucher();
110 bzero(msg
, sizeof(msg_store
));
112 msg
->msgh_local_port
= ePort
;
113 msg
->msgh_size
= MSG
;
114 kr
= mach_msg_receive(msg
);
115 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "exception msg recv");
117 bzero(reply_store
, sizeof(reply_store
));
119 switch (reply_type
) {
120 case ReplyWithNoError
: {
123 mach_msg_header_t hdr
;
128 reply_fmt_t
*reply
= (reply_fmt_t
*)reply_store
;
130 reply
->hdr
.msgh_bits
= MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MOVE_SEND_ONCE
, 0, 0, 0);
131 reply
->hdr
.msgh_remote_port
= msg
->msgh_remote_port
;
132 reply
->hdr
.msgh_local_port
= MACH_PORT_NULL
;
133 reply
->hdr
.msgh_size
= sizeof(*reply
);
134 reply
->hdr
.msgh_id
= msg
->msgh_id
+ 100;
138 case ReplyWithReplyPort
: {
141 mach_msg_header_t hdr
;
146 reply_fmt_t
*reply
= (reply_fmt_t
*)reply_store
;
148 reply
->hdr
.msgh_bits
= MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MOVE_SEND_ONCE
, MACH_MSG_TYPE_COPY_SEND
, 0, 0);
149 reply
->hdr
.msgh_remote_port
= msg
->msgh_remote_port
;
150 reply
->hdr
.msgh_local_port
= ePort
; /* Bogus */
151 reply
->hdr
.msgh_size
= sizeof(*reply
);
152 reply
->hdr
.msgh_id
= msg
->msgh_id
+ 100;
156 case ReplyWithReplyPortMove
: {
159 mach_msg_header_t hdr
;
164 reply_fmt_t
*reply
= (reply_fmt_t
*)reply_store
;
166 reply
->hdr
.msgh_bits
= MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MOVE_SEND_ONCE
, MACH_MSG_TYPE_MOVE_SEND
, 0, 0);
167 reply
->hdr
.msgh_remote_port
= msg
->msgh_remote_port
;
168 reply
->hdr
.msgh_local_port
= ePort
; /* Bogus */
169 reply
->hdr
.msgh_size
= sizeof(*reply
);
170 reply
->hdr
.msgh_id
= msg
->msgh_id
+ 100;
174 case ReplyWithReplyPortCplxBit
: {
177 mach_msg_header_t hdr
;
178 mach_msg_body_t body
;
181 reply_fmt_t
*reply
= (reply_fmt_t
*)reply_store
;
183 reply
->hdr
.msgh_bits
= MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MOVE_SEND_ONCE
, MACH_MSG_TYPE_COPY_SEND
, 0, MACH_MSGH_BITS_COMPLEX
);
184 reply
->hdr
.msgh_remote_port
= msg
->msgh_remote_port
;
185 reply
->hdr
.msgh_local_port
= ePort
; /* Bogus */
186 reply
->hdr
.msgh_size
= sizeof(*reply
);
187 reply
->hdr
.msgh_id
= msg
->msgh_id
+ 100;
188 reply
->body
.msgh_descriptor_count
= 0;
192 case ReplyWithReplyPortMoveCplxBit
: {
195 mach_msg_header_t hdr
;
196 mach_msg_body_t body
;
199 reply_fmt_t
*reply
= (reply_fmt_t
*)reply_store
;
201 reply
->hdr
.msgh_bits
= MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MOVE_SEND_ONCE
, MACH_MSG_TYPE_MOVE_SEND
, 0, MACH_MSGH_BITS_COMPLEX
);
202 reply
->hdr
.msgh_remote_port
= msg
->msgh_remote_port
;
203 reply
->hdr
.msgh_local_port
= ePort
; /* Bogus */
204 reply
->hdr
.msgh_size
= sizeof(*reply
);
205 reply
->hdr
.msgh_id
= msg
->msgh_id
+ 100;
206 reply
->body
.msgh_descriptor_count
= 0;
210 case ReplyWithPortDesc
: {
213 mach_msg_header_t hdr
;
214 mach_msg_body_t body
;
215 mach_msg_port_descriptor_t port
;
218 reply_fmt_t
*reply
= (reply_fmt_t
*)reply_store
;
220 reply
->hdr
.msgh_bits
= MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MOVE_SEND_ONCE
, 0, 0, MACH_MSGH_BITS_COMPLEX
);
221 reply
->hdr
.msgh_remote_port
= msg
->msgh_remote_port
;
222 reply
->hdr
.msgh_local_port
= MACH_PORT_NULL
;
223 reply
->hdr
.msgh_size
= sizeof(*reply
);
224 reply
->hdr
.msgh_id
= msg
->msgh_id
+ 100;
225 reply
->body
.msgh_descriptor_count
= 1;
226 reply
->port
.type
= MACH_MSG_PORT_DESCRIPTOR
;
227 reply
->port
.name
= ePort
;
228 reply
->port
.disposition
= MACH_MSG_TYPE_COPY_SEND
;
232 case ReplyWithOOLDesc
: {
235 mach_msg_header_t hdr
;
236 mach_msg_body_t body
;
237 mach_msg_ool_descriptor_t ool
;
240 reply_fmt_t
*reply
= (reply_fmt_t
*)reply_store
;
242 reply
->hdr
.msgh_bits
= MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MOVE_SEND_ONCE
, 0, 0, MACH_MSGH_BITS_COMPLEX
);
243 reply
->hdr
.msgh_remote_port
= msg
->msgh_remote_port
;
244 reply
->hdr
.msgh_local_port
= MACH_PORT_NULL
;
245 reply
->hdr
.msgh_size
= sizeof(*reply
);
246 reply
->hdr
.msgh_id
= msg
->msgh_id
+ 100;
247 reply
->body
.msgh_descriptor_count
= 1;
248 reply
->ool
.type
= MACH_MSG_OOL_DESCRIPTOR
;
249 reply
->ool
.address
= (void *)page
;
250 reply
->ool
.size
= PG_ALLOC
;
251 reply
->ool
.deallocate
= 0;
252 reply
->ool
.copy
= MACH_MSG_VIRTUAL_COPY
;
256 case ReplyWithVoucher
: {
259 mach_msg_header_t hdr
;
264 reply_fmt_t
*reply
= (reply_fmt_t
*)reply_store
;
266 reply
->hdr
.msgh_remote_port
= msg
->msgh_remote_port
;
267 reply
->hdr
.msgh_local_port
= MACH_PORT_NULL
;
268 reply
->hdr
.msgh_size
= sizeof(*reply
);
269 reply
->hdr
.msgh_id
= msg
->msgh_id
+ 100;
270 reply
->kr
= KERN_SUCCESS
;
272 /* try to send a voucher */
273 reply
->hdr
.msgh_bits
= MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MOVE_SEND_ONCE
,
275 MACH_MSG_TYPE_MOVE_SEND
,
277 reply
->hdr
.msgh_voucher_port
= voucher
;
278 voucher
= MACH_VOUCHER_NULL
;
282 case ReplyWithVoucherGarbage
: {
285 mach_msg_header_t hdr
;
290 reply_fmt_t
*reply
= (reply_fmt_t
*)reply_store
;
292 reply
->hdr
.msgh_remote_port
= msg
->msgh_remote_port
;
293 reply
->hdr
.msgh_local_port
= MACH_PORT_NULL
;
294 reply
->hdr
.msgh_size
= sizeof(*reply
);
295 reply
->hdr
.msgh_id
= msg
->msgh_id
+ 100;
296 reply
->kr
= KERN_SUCCESS
;
298 /* don't claim to send a voucher */
299 reply
->hdr
.msgh_bits
= MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MOVE_SEND_ONCE
,
301 /* but put some bits in the field */
302 reply
->hdr
.msgh_voucher_port
= (mach_voucher_t
)0xdead;
307 T_ASSERT_FAIL("Invalid ReplyType: %d", reply_type
);
312 kr
= mach_port_mod_refs(mach_task_self(), voucher
,
313 MACH_PORT_RIGHT_SEND
, -1);
314 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "destroy voucher");
317 T_LOG("sending exception reply of type (%s)", reply_type_str(reply_type
));
318 kr
= mach_msg_send((mach_msg_header_t
*)reply_store
);
319 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "exception reply msg send");
321 T_PASS("Successfully delivered exception reply message of type %s", reply_type_str(reply_type
));
327 static sigjmp_buf jb
;
328 static int *bad_pointer
= NULL
;
329 static int s_sigmask
= 0;
332 signal_handler(int sig
, siginfo_t
*sip __unused
, void *ucontext __unused
)
334 if (sigmask(sig
) & s_sigmask
) { /* TODO: check that the fault was generated by us */
337 siglongjmp(jb
, -sig
);
346 struct sigaction sa
= {
347 .sa_sigaction
= signal_handler
,
348 .sa_flags
= SA_SIGINFO
350 sigfillset(&sa
.sa_mask
);
352 T_QUIET
; T_ASSERT_POSIX_ZERO(sigaction(SIGTRAP
, &sa
, NULL
), NULL
);
353 mask
|= sigmask(SIGTRAP
);
355 T_QUIET
; T_ASSERT_POSIX_ZERO(sigaction(SIGSEGV
, &sa
, NULL
), NULL
);
356 mask
|= sigmask(SIGSEGV
);
358 T_QUIET
; T_ASSERT_POSIX_ZERO(sigaction(SIGILL
, &sa
, NULL
), NULL
);
359 mask
|= sigmask(SIGILL
);
365 test_exc_reply_type(ReplyType reply_type
)
368 task_t me
= mach_task_self();
369 thread_t self
= mach_thread_self();
370 pthread_t handler_thread
;
374 s_sigmask
= handle_signals();
375 T_LOG("task self = 0x%x, thread self = 0x%x\n", me
, self
);
377 kr
= mach_port_allocate(me
, MACH_PORT_RIGHT_RECEIVE
, &ePort
);
378 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "allocate receive right");
380 kr
= mach_port_insert_right(me
, ePort
, ePort
, MACH_MSG_TYPE_MAKE_SEND
);
381 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "insert right into port=[%d]", ePort
);
383 kr
= thread_set_exception_ports(self
, EXC_MASK_ALL
, ePort
, EXCEPTION_DEFAULT
, THREAD_STATE_NONE
);
384 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "set exception ports on self=[%d], handler=[%d]", self
, ePort
);
386 pthread_attr_init(&attr
);
387 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
388 struct exc_thread_arg
*ta
= (struct exc_thread_arg
*)malloc(sizeof(*ta
));
389 T_QUIET
; T_ASSERT_NOTNULL(ta
, "exception handler thread args allocation");
393 T_QUIET
; T_ASSERT_POSIX_SUCCESS(pthread_create(&handler_thread
, &attr
, handle_exceptions
, (void *)ta
),
396 pthread_attr_destroy(&attr
);
398 /* cause exception! */
399 int x
= sigsetjmp(jb
, 0); //s_sigmask);
403 T_FAIL("Unexpected state on return-from-exception");
406 T_PASS("Successfully recovered from exception");
409 T_FAIL("Unexpected end of test!");
413 T_DECL(mach_exc_ReplyNoError
, "exception server reply with no error",
414 T_META_CHECK_LEAKS(false), T_META_IGNORECRASHES(".*mach_exception_reply.*"))
416 test_exc_reply_type(ReplyWithNoError
);
418 T_DECL(mach_exc_ReplyWithReplyPort
, "exception server reply with reply port",
419 T_META_CHECK_LEAKS(false), T_META_IGNORECRASHES(".*mach_exception_reply.*"))
421 test_exc_reply_type(ReplyWithReplyPort
);
423 T_DECL(mach_exc_ReplyWithReplyPortMove
, "exception server reply with reply port as MOVE_SEND",
424 T_META_CHECK_LEAKS(false), T_META_IGNORECRASHES(".*mach_exception_reply.*"))
426 test_exc_reply_type(ReplyWithReplyPortMove
);
428 T_DECL(mach_exc_ReplyWithReplyPortCplxBit
, "exception server reply with reply port and complex bit set",
429 T_META_CHECK_LEAKS(false), T_META_IGNORECRASHES(".*mach_exception_reply.*"))
431 test_exc_reply_type(ReplyWithReplyPortCplxBit
);
433 T_DECL(mach_exc_ReplyWithReplyPortMoveCplxBit
, "exception server reply with reply port as MOVE_SEND and complex bit set",
434 T_META_CHECK_LEAKS(false), T_META_IGNORECRASHES(".*mach_exception_reply.*"))
436 test_exc_reply_type(ReplyWithReplyPortMoveCplxBit
);
438 T_DECL(mach_exc_ReplyWithOOLPort
, "exception server reply with OOL port descriptor",
439 T_META_CHECK_LEAKS(false), T_META_IGNORECRASHES(".*mach_exception_reply.*"))
441 test_exc_reply_type(ReplyWithPortDesc
);
443 T_DECL(mach_exc_ReplyWithOOLDesc
, "exception server reply with OOL memory descriptor",
444 T_META_CHECK_LEAKS(false), T_META_IGNORECRASHES(".*mach_exception_reply.*"))
446 test_exc_reply_type(ReplyWithOOLDesc
);
448 T_DECL(mach_exc_ReplyWithVoucher
, "exception server reply with a voucher",
449 T_META_CHECK_LEAKS(false), T_META_IGNORECRASHES(".*mach_exception_reply.*"))
451 test_exc_reply_type(ReplyWithVoucher
);
453 T_DECL(mach_exc_ReplyWithVoucherGarbage
, "exception server reply with bits in msgh_voucher_port",
454 T_META_CHECK_LEAKS(false), T_META_IGNORECRASHES(".*mach_exception_reply.*"))
456 test_exc_reply_type(ReplyWithVoucherGarbage
);