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