xref: /xnu-11215.1.10/tests/voucher_entry_18826844.c (revision 8d741a5de7ff4191bf97d57b9f54c2f6d4a15585)
1*8d741a5dSApple OSS Distributions /*
2*8d741a5dSApple OSS Distributions  * Test that sending a message to a voucher with the same voucher as the voucher port
3*8d741a5dSApple OSS Distributions  * with only one send right count with move send before the copy send doesn't panic.
4*8d741a5dSApple OSS Distributions  *
5*8d741a5dSApple OSS Distributions  * clang -o voucherentry voucherentry.c -ldarwintest -Weverything -Wno-gnu-flexible-array-initializer
6*8d741a5dSApple OSS Distributions  *
7*8d741a5dSApple OSS Distributions  * <rdar://problem/18826844>
8*8d741a5dSApple OSS Distributions  */
9*8d741a5dSApple OSS Distributions 
10*8d741a5dSApple OSS Distributions #include <mach/mach.h>
11*8d741a5dSApple OSS Distributions #include <darwintest.h>
12*8d741a5dSApple OSS Distributions 
13*8d741a5dSApple OSS Distributions T_GLOBAL_META(
14*8d741a5dSApple OSS Distributions 	T_META_NAMESPACE("xnu.ipc"),
15*8d741a5dSApple OSS Distributions 	T_META_RUN_CONCURRENTLY(TRUE),
16*8d741a5dSApple OSS Distributions 	T_META_RADAR_COMPONENT_NAME("xnu"),
17*8d741a5dSApple OSS Distributions 	T_META_RADAR_COMPONENT_VERSION("IPC"));
18*8d741a5dSApple OSS Distributions 
19*8d741a5dSApple OSS Distributions T_DECL(voucher_entry, "voucher_entry", T_META_CHECK_LEAKS(false), T_META_ALL_VALID_ARCHS(true), T_META_TAG_VM_PREFERRED)
20*8d741a5dSApple OSS Distributions {
21*8d741a5dSApple OSS Distributions 	kern_return_t kr        = KERN_SUCCESS;
22*8d741a5dSApple OSS Distributions 	mach_voucher_t voucher  = MACH_VOUCHER_NULL;
23*8d741a5dSApple OSS Distributions 	mach_port_name_t reply;
24*8d741a5dSApple OSS Distributions 	mach_port_options_t opts = {
25*8d741a5dSApple OSS Distributions 		.flags = MPO_REPLY_PORT,
26*8d741a5dSApple OSS Distributions 	};
27*8d741a5dSApple OSS Distributions 
28*8d741a5dSApple OSS Distributions 	/*
29*8d741a5dSApple OSS Distributions 	 * The bank voucher already exists in this process, so using it doesn't
30*8d741a5dSApple OSS Distributions 	 * actually test the problem. Use an importance voucher instead.
31*8d741a5dSApple OSS Distributions 	 */
32*8d741a5dSApple OSS Distributions 	mach_voucher_attr_recipe_data_t recipe = {
33*8d741a5dSApple OSS Distributions 		.key                = MACH_VOUCHER_ATTR_KEY_IMPORTANCE,
34*8d741a5dSApple OSS Distributions 		.command            = MACH_VOUCHER_ATTR_IMPORTANCE_SELF,
35*8d741a5dSApple OSS Distributions 		.previous_voucher   = MACH_VOUCHER_NULL,
36*8d741a5dSApple OSS Distributions 		.content_size       = 0,
37*8d741a5dSApple OSS Distributions 	};
38*8d741a5dSApple OSS Distributions 
39*8d741a5dSApple OSS Distributions 	kr = host_create_mach_voucher(mach_host_self(),
40*8d741a5dSApple OSS Distributions 	    (mach_voucher_attr_raw_recipe_array_t)&recipe,
41*8d741a5dSApple OSS Distributions 	    sizeof(recipe), &voucher);
42*8d741a5dSApple OSS Distributions 
43*8d741a5dSApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(kr, "host_create_mach_voucher");
44*8d741a5dSApple OSS Distributions 
45*8d741a5dSApple OSS Distributions 	T_ASSERT_NOTNULL(voucher, "voucher must not be null");
46*8d741a5dSApple OSS Distributions 
47*8d741a5dSApple OSS Distributions 	mach_port_urefs_t refs = 0;
48*8d741a5dSApple OSS Distributions 
49*8d741a5dSApple OSS Distributions 	kr = mach_port_get_refs(mach_task_self(), voucher, MACH_PORT_RIGHT_SEND, &refs);
50*8d741a5dSApple OSS Distributions 
51*8d741a5dSApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(kr, "mach_port_get_refs");
52*8d741a5dSApple OSS Distributions 
53*8d741a5dSApple OSS Distributions 	T_ASSERT_EQ(refs, (mach_port_urefs_t)1, "voucher must have only one ref");
54*8d741a5dSApple OSS Distributions 
55*8d741a5dSApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(mach_port_construct(mach_task_self(),
56*8d741a5dSApple OSS Distributions 	    &opts, 0, &reply), "make reply port");
57*8d741a5dSApple OSS Distributions 
58*8d741a5dSApple OSS Distributions 	/* First, try with two moves (must fail because there's only one ref) */
59*8d741a5dSApple OSS Distributions 	mach_msg_header_t request_msg_1 = {
60*8d741a5dSApple OSS Distributions 		.msgh_remote_port   = voucher,
61*8d741a5dSApple OSS Distributions 		.msgh_local_port    = reply,
62*8d741a5dSApple OSS Distributions 		.msgh_voucher_port  = voucher,
63*8d741a5dSApple OSS Distributions 		.msgh_bits          = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MOVE_SEND,
64*8d741a5dSApple OSS Distributions 	    MACH_MSG_TYPE_MAKE_SEND_ONCE, MACH_MSG_TYPE_MOVE_SEND, 0),
65*8d741a5dSApple OSS Distributions 		.msgh_id            = 0xDEAD,
66*8d741a5dSApple OSS Distributions 		.msgh_size          = sizeof(request_msg_1),
67*8d741a5dSApple OSS Distributions 	};
68*8d741a5dSApple OSS Distributions 
69*8d741a5dSApple OSS Distributions 	kr = mach_msg2(&request_msg_1, MACH64_SEND_MSG | MACH64_RCV_MSG | MACH64_SEND_KOBJECT_CALL,
70*8d741a5dSApple OSS Distributions 	    request_msg_1, request_msg_1.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, 0);
71*8d741a5dSApple OSS Distributions 
72*8d741a5dSApple OSS Distributions 	T_ASSERT_MACH_ERROR(MACH_SEND_INVALID_DEST, kr, "send with two moves should fail with invalid dest");
73*8d741a5dSApple OSS Distributions 
74*8d741a5dSApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(mach_port_destruct(mach_task_self(), reply, 0, 0),
75*8d741a5dSApple OSS Distributions 	    "destroy reply port");
76*8d741a5dSApple OSS Distributions 
77*8d741a5dSApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(mach_port_construct(mach_task_self(),
78*8d741a5dSApple OSS Distributions 	    &opts, 0, &reply), "make reply port");
79*8d741a5dSApple OSS Distributions 
80*8d741a5dSApple OSS Distributions 	/* Next, try with a move and a copy (will succeed and destroy the last ref) */
81*8d741a5dSApple OSS Distributions 	union {
82*8d741a5dSApple OSS Distributions 		mach_msg_header_t hdr;
83*8d741a5dSApple OSS Distributions 		struct {
84*8d741a5dSApple OSS Distributions 			mig_reply_error_t err;
85*8d741a5dSApple OSS Distributions 			mach_msg_trailer_t trailer;
86*8d741a5dSApple OSS Distributions 		};
87*8d741a5dSApple OSS Distributions 	} request_msg_2 = {
88*8d741a5dSApple OSS Distributions 		.hdr = {
89*8d741a5dSApple OSS Distributions 			.msgh_remote_port   = voucher,
90*8d741a5dSApple OSS Distributions 			.msgh_local_port    = reply,
91*8d741a5dSApple OSS Distributions 			.msgh_voucher_port  = voucher,
92*8d741a5dSApple OSS Distributions 			.msgh_bits          = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MOVE_SEND,
93*8d741a5dSApple OSS Distributions 	    MACH_MSG_TYPE_MAKE_SEND_ONCE, MACH_MSG_TYPE_COPY_SEND, 0),
94*8d741a5dSApple OSS Distributions 			.msgh_id            = 0xDEAD,
95*8d741a5dSApple OSS Distributions 			.msgh_size          = sizeof(request_msg_2),
96*8d741a5dSApple OSS Distributions 		}
97*8d741a5dSApple OSS Distributions 	};
98*8d741a5dSApple OSS Distributions 
99*8d741a5dSApple OSS Distributions 	/* panic happens here */
100*8d741a5dSApple OSS Distributions 	kr = mach_msg2(&request_msg_2, MACH64_SEND_MSG | MACH64_RCV_MSG | MACH64_SEND_KOBJECT_CALL,
101*8d741a5dSApple OSS Distributions 	    request_msg_2.hdr, request_msg_2.hdr.msgh_size, sizeof(request_msg_2),
102*8d741a5dSApple OSS Distributions 	    reply, MACH_MSG_TIMEOUT_NONE, 0);
103*8d741a5dSApple OSS Distributions 
104*8d741a5dSApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(kr, "send with move and copy succeeds");
105*8d741a5dSApple OSS Distributions 
106*8d741a5dSApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(mach_port_destruct(mach_task_self(), reply, 0, 0),
107*8d741a5dSApple OSS Distributions 	    "destroy reply port");
108*8d741a5dSApple OSS Distributions 
109*8d741a5dSApple OSS Distributions 	kr = mach_port_get_refs(mach_task_self(), voucher, MACH_PORT_RIGHT_SEND, &refs);
110*8d741a5dSApple OSS Distributions 
111*8d741a5dSApple OSS Distributions 	T_ASSERT_MACH_ERROR(KERN_INVALID_NAME, kr, "voucher should now be invalid name");
112*8d741a5dSApple OSS Distributions }
113