xref: /xnu-12377.81.4/tests/ipc/mach_port_construct_errors.c (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <mach/mach.h>
4 #include <mach/mach_port.h>
5 #include <sys/code_signing.h>
6 #include <sys/sysctl.h>
7 #include <darwintest.h>
8 
9 T_GLOBAL_META(
10 	T_META_NAMESPACE("xnu.ipc"),
11 	T_META_RUN_CONCURRENTLY(TRUE),
12 	T_META_RADAR_COMPONENT_NAME("xnu"),
13 	T_META_RADAR_COMPONENT_VERSION("IPC"),
14 	T_META_TAG_VM_PREFERRED);
15 
16 #define countof(x) (sizeof(x) / sizeof(x[0]))
17 
18 static void
19 expect_sigkill(
20 	void (^fn)(void),
21 	const char *description)
22 {
23 	pid_t pid = fork();
24 	T_QUIET; T_ASSERT_POSIX_SUCCESS(pid, "fork");
25 
26 	if (pid == 0) {
27 		fn();
28 		T_ASSERT_FAIL("%s: did not receive SIGKILL", description);
29 	} else {
30 		int status = 0;
31 		T_QUIET; T_ASSERT_POSIX_SUCCESS(waitpid(pid, &status, 0), "waitpid");
32 		T_EXPECT_EQ(WTERMSIG(status), SIGKILL,
33 		    "%s exited with %d, expect SIGKILL", description, WTERMSIG(status));
34 	}
35 }
36 
37 T_DECL(mach_port_construct_at_most_one,
38     "mach_port_construct at most one flag policy")
39 {
40 	/* verify our at most one flag rule is enforced */
41 	const uint32_t at_most_one_flags[] = {
42 		MPO_REPLY_PORT,
43 		MPO_CONNECTION_PORT,
44 		MPO_SERVICE_PORT,
45 		MPO_PROVISIONAL_REPLY_PORT,
46 		MPO_EXCEPTION_PORT,
47 		MPO_CONNECTION_PORT_WITH_PORT_ARRAY
48 	};
49 
50 
51 	for (uint32_t i = 0; i < countof(at_most_one_flags) - 1; ++i) {
52 		for (uint32_t j = i + 1; j < countof(at_most_one_flags); ++j) {
53 			mach_port_t port;
54 
55 			mach_port_options_t opts = {
56 				.flags = at_most_one_flags[i] | at_most_one_flags[j]
57 			};
58 
59 			kern_return_t kr = mach_port_construct(mach_task_self(), &opts, 0x0, &port);
60 			T_ASSERT_MACH_ERROR(kr,
61 			    KERN_INVALID_ARGUMENT, "mach_port_construct failed for at most one flags");
62 		}
63 	}
64 }
65 
66 T_DECL(mach_port_construct_invalid_arguments_and_values,
67     "mach_port_construct invalid arguments and values")
68 {
69 	kern_return_t kr;
70 	mach_port_t port;
71 
72 	mach_port_options_t conn_opts = {
73 		.flags = MPO_CONNECTION_PORT,
74 		.service_port_name = 0x0
75 	};
76 
77 	kr = mach_port_construct(mach_task_self(), &conn_opts, 0x0, &port);
78 	T_ASSERT_MACH_ERROR(kr,
79 	    KERN_INVALID_ARGUMENT,
80 	    "MPO_CONNECTION_PORT failed on service_port_name");
81 
82 	conn_opts.service_port_name = MPO_ANONYMOUS_SERVICE;
83 
84 	kr = mach_port_construct(mach_task_self(), &conn_opts, 0x0, &port);
85 	T_ASSERT_MACH_SUCCESS(kr, "MPO_CONNECTION_PORT succeeds with anonymous service name");
86 	kr = mach_port_destruct(mach_task_self(), port, 0, 0);
87 	T_ASSERT_MACH_SUCCESS(kr, "destroy anonymous service name");
88 
89 	mach_port_options_t qlimit_opts = {
90 		.flags = MPO_QLIMIT,
91 		.mpl.mpl_qlimit = MACH_PORT_QLIMIT_MAX + 1
92 	};
93 
94 	kr = mach_port_construct(mach_task_self(), &qlimit_opts, 0x0, &port);
95 	T_ASSERT_MACH_ERROR(kr,
96 	    KERN_INVALID_VALUE,
97 	    "MPO_QLIMIT failed on invalid value");
98 
99 	/* Enumerate on all unknown MPO flags */
100 	mach_port_options_t unknown_flags_opts;
101 	for (uint32_t i = 0; i < sizeof(unknown_flags_opts.flags) * CHAR_BIT; ++i) {
102 		unknown_flags_opts.flags = MPO_UNUSED_BITS & (1 << i);
103 
104 		if (unknown_flags_opts.flags != 0) {
105 			kr = mach_port_construct(mach_task_self(), &unknown_flags_opts, 0x0, &port);
106 			T_ASSERT_MACH_ERROR(kr,
107 			    KERN_INVALID_ARGUMENT,
108 			    "Unknown MPO flags 0x%x failed with KERN_INVALID_ARGUMENT",
109 			    unknown_flags_opts.flags);
110 		}
111 	}
112 }
113 
114 T_DECL(mach_port_construct_fatal_failure,
115     "mach_port_construct kern defined fatal failures",
116     T_META_IGNORECRASHES(".*mach_port_construct_errors.*"),
117     T_META_ENABLED(!TARGET_OS_OSX && !TARGET_OS_BRIDGE))
118 {
119 	expect_sigkill(^{
120 		mach_port_t port;
121 		mach_port_options_t opts = {
122 		        .flags = MPO_CONNECTION_PORT_WITH_PORT_ARRAY
123 		};
124 		(void)mach_port_construct(mach_task_self(), &opts, 0x0, &port);
125 	}, "passing MPO_CONNECTION_PORT_WITH_PORT_ARRAY without entitlement");
126 }
127 
128 T_DECL(mach_port_construct_kern_denied,
129     "mach_port_construct kern defined failures",
130     T_META_TAG_VM_PREFERRED,
131     T_META_ENABLED(!TARGET_OS_OSX && !TARGET_OS_BRIDGE))
132 {
133 	kern_return_t kr;
134 	mach_port_t port;
135 	mach_port_options_t opts;
136 
137 	/*
138 	 * should fail because only TASK_GRAPHICS_SERVER is allowed to
139 	 * use MPO_TG_BLOCK_TRACKING.
140 	 */
141 	opts.flags = MPO_TG_BLOCK_TRACKING;
142 
143 	kr = mach_port_construct(mach_task_self(), &opts, 0x0, &port);
144 	T_ASSERT_MACH_ERROR(kr,
145 	    KERN_DENIED, "MPO_TG_BLOCK_TRACKING failed with KERN_DENIED");
146 }
147