xref: /xnu-11215.1.10/tests/extract_right_soft_fail.c (revision 8d741a5de7ff4191bf97d57b9f54c2f6d4a15585)
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <darwintest.h>
5 #include <mach/mach.h>
6 #include <mach/mach_vm.h>
7 #include <sys/sysctl.h>
8 #include <spawn.h>
9 #include <signal.h>
10 #import <System/sys/codesign.h>
11 
12 #define IKOT_TASK_CONTROL 2
13 
14 T_GLOBAL_META(
15 	T_META_NAMESPACE("xnu.ipc"),
16 	T_META_RADAR_COMPONENT_NAME("xnu"),
17 	T_META_RADAR_COMPONENT_VERSION("IPC"),
18 	T_META_RUN_CONCURRENTLY(TRUE),
19 	T_META_TAG_VM_PREFERRED);
20 
21 static void
test_extract_immovable_task_port(pid_t pid)22 test_extract_immovable_task_port(pid_t pid)
23 {
24 	kern_return_t kr;
25 	mach_port_t tport = MACH_PORT_NULL;
26 	ipc_info_space_t space_info;
27 	ipc_info_name_array_t table;
28 	mach_msg_type_number_t tableCount;
29 	ipc_info_tree_name_array_t tree; /* unused */
30 	mach_msg_type_number_t treeCount; /* unused */
31 
32 	mach_port_t extracted;
33 	mach_msg_type_name_t right;
34 
35 
36 	kr = task_for_pid(mach_task_self(), pid, &tport);
37 	T_EXPECT_MACH_SUCCESS(kr, "task_for_pid(), tport: 0x%x", tport);
38 
39 	T_LOG("Target pid: %d", pid);
40 
41 	if (pid == getpid()) {
42 		/* self extraction should succeed */
43 		kr = mach_port_extract_right(mach_task_self(), mach_task_self(), MACH_MSG_TYPE_COPY_SEND, &extracted, &right);
44 		T_EXPECT_MACH_SUCCESS(kr, "mach_port_extract_right() on immovable port in current space should succeed");
45 	} else {
46 		unsigned int kotype = 0, kobject = 0;
47 		mach_port_name_t tport_name = MACH_PORT_NULL;
48 		int tport_idx = 0;
49 		kr = mach_port_space_info(tport, &space_info, &table, &tableCount, &tree, &treeCount);
50 		T_EXPECT_MACH_SUCCESS(kr, "mach_port_space_info()");
51 
52 		for (int i = 0; i < tableCount; i++) {
53 			T_LOG("Searching for task port..name: 0x%x", table[i].iin_name);
54 			kr = mach_port_kernel_object(tport, table[i].iin_name, &kotype, &kobject);
55 			if (KERN_SUCCESS == kr && kotype == IKOT_TASK_CONTROL) {
56 				tport_name = table[i].iin_name;
57 				tport_idx = i;
58 				break;
59 			} else if (kr) {
60 				T_LOG("mach_port_kernel_object() failed on name 0x%x, kr: 0x%x", table[i].iin_name, kr);
61 			}
62 		}
63 
64 		if (!tport_name) {
65 			T_FAIL("Did not find task port in child's space");
66 		}
67 		T_LOG("Remote tport name: 0x%x", tport_name);
68 		kr = mach_port_extract_right(tport, tport_name, MACH_MSG_TYPE_COPY_SEND, &extracted, &right);
69 		T_EXPECT_EQ(kr, KERN_INVALID_CAPABILITY, "mach_port_extract_right() on immovable port in child's space should fail (no crash): 0x%x", kr);
70 
71 		T_LOG("Still alive after extract right..");
72 
73 		kr = mach_port_mod_refs(tport, tport_name, MACH_PORT_RIGHT_SEND, -table[tport_idx].iin_urefs);
74 		T_EXPECT_EQ(kr, KERN_INVALID_CAPABILITY, "mach_port_mod_refs() on pinned port in child's space should fail (no crash): 0x%x", kr);
75 
76 		T_LOG("Still alive after deallocate..");
77 	}
78 }
79 
80 T_DECL(extract_right_soft_fail, "Immovable/pinned violation on foreign task's space should not crash caller",
81     T_META_CHECK_LEAKS(false))
82 {
83 	uint32_t opts = 0;
84 	size_t size = sizeof(&opts);
85 	pid_t child_pid;
86 	kern_return_t ret;
87 	int status, fd[2], fd2[2];
88 
89 	T_LOG("Check if immovable control port has been enabled\n");
90 	ret = sysctlbyname("kern.ipc_control_port_options", &opts, &size, NULL, 0);
91 
92 	if (!ret && (opts & 0x08) == 0) {
93 		T_SKIP("1p immovable control port hard enforcement isn't enabled");
94 	}
95 
96 	/* extracting mach_task_self() should succeed */
97 	test_extract_immovable_task_port(getpid());
98 
99 	ret = pipe(fd);
100 	T_EXPECT_NE(ret, -1, "pipe creation");
101 
102 	ret = pipe(fd2);
103 	T_EXPECT_NE(ret, -1, "pipe creation2");
104 
105 	child_pid = fork();
106 
107 	if (child_pid < 0) {
108 		T_FAIL("fork failed()");
109 	}
110 
111 	if (child_pid == 0) {
112 		char data[6];
113 		close(fd[0]);
114 		close(fd2[1]);
115 		write(fd[1], "wakeup", 6); /* Sync point 1 */
116 		close(fd[1]);
117 
118 		read(fd2[0], data, 6); /* Sync point 2 */
119 		close(fd2[0]);
120 	} else {
121 		char data[6];
122 		close(fd[1]);
123 		close(fd2[0]);
124 		read(fd[0], data, 6); /* Sync point 1 */
125 		close(fd[0]);
126 
127 		/* extracting child's immovable task port should fail without crash */
128 		test_extract_immovable_task_port(child_pid);
129 
130 		write(fd2[1], "wakeup", 6); /* Sync point 2 */
131 		close(fd2[1]);
132 
133 		kill(child_pid, SIGKILL);
134 		wait(&status);
135 	}
136 }
137