xref: /xnu-11215.61.5/tests/sysctl_get_owned_vmobjects.c (revision 4f1223e81cd707a65cc109d0b8ad6653699da3c4)
1*4f1223e8SApple OSS Distributions #include <darwintest.h>
2*4f1223e8SApple OSS Distributions #include <darwintest_utils.h>
3*4f1223e8SApple OSS Distributions #include <mach/mach.h>
4*4f1223e8SApple OSS Distributions #include <mach/task_info.h>
5*4f1223e8SApple OSS Distributions #include <mach/vm_region.h>
6*4f1223e8SApple OSS Distributions #include <mach/mach_vm.h>
7*4f1223e8SApple OSS Distributions #include <sys/kern_sysctl.h>
8*4f1223e8SApple OSS Distributions #include <errno.h>
9*4f1223e8SApple OSS Distributions 
10*4f1223e8SApple OSS Distributions T_GLOBAL_META(
11*4f1223e8SApple OSS Distributions 	T_META_NAMESPACE("xnu.vm"),
12*4f1223e8SApple OSS Distributions 	T_META_RADAR_COMPONENT_NAME("xnu"),
13*4f1223e8SApple OSS Distributions 	T_META_RADAR_COMPONENT_VERSION("VM"));
14*4f1223e8SApple OSS Distributions 
15*4f1223e8SApple OSS Distributions static const char* g_sysctl_name = "vm.get_owned_vmobjects";
16*4f1223e8SApple OSS Distributions 
17*4f1223e8SApple OSS Distributions mach_port_t get_corpse(void);
18*4f1223e8SApple OSS Distributions 
19*4f1223e8SApple OSS Distributions mach_port_t
get_corpse()20*4f1223e8SApple OSS Distributions get_corpse()
21*4f1223e8SApple OSS Distributions {
22*4f1223e8SApple OSS Distributions 	kern_return_t kr;
23*4f1223e8SApple OSS Distributions 	mach_port_t corpse_port;
24*4f1223e8SApple OSS Distributions 
25*4f1223e8SApple OSS Distributions 	kr = task_generate_corpse(mach_task_self(), &corpse_port);
26*4f1223e8SApple OSS Distributions 	if (kr != KERN_SUCCESS) {
27*4f1223e8SApple OSS Distributions 		mach_error("task_generate_corpse failed", kr);
28*4f1223e8SApple OSS Distributions 		corpse_port = MACH_PORT_NULL;
29*4f1223e8SApple OSS Distributions 
30*4f1223e8SApple OSS Distributions 		switch (kr) {
31*4f1223e8SApple OSS Distributions 		case KERN_NOT_SUPPORTED:
32*4f1223e8SApple OSS Distributions 		case KERN_FAILURE:
33*4f1223e8SApple OSS Distributions 		case KERN_RESOURCE_SHORTAGE:
34*4f1223e8SApple OSS Distributions 			break;
35*4f1223e8SApple OSS Distributions 		default:
36*4f1223e8SApple OSS Distributions 			/* convert to KERN_FAILURE after logging to catch other rc codes */
37*4f1223e8SApple OSS Distributions 			/* and trigger test failure */
38*4f1223e8SApple OSS Distributions 			kr = KERN_FAILURE;
39*4f1223e8SApple OSS Distributions 			break;
40*4f1223e8SApple OSS Distributions 		}
41*4f1223e8SApple OSS Distributions 	}
42*4f1223e8SApple OSS Distributions 
43*4f1223e8SApple OSS Distributions 	/* anything other than KERN_FAILURE is valid */
44*4f1223e8SApple OSS Distributions 	T_EXPECT_NE(kr, KERN_FAILURE, "corpse creation\n");
45*4f1223e8SApple OSS Distributions 
46*4f1223e8SApple OSS Distributions 	return corpse_port;
47*4f1223e8SApple OSS Distributions }
48*4f1223e8SApple OSS Distributions 
49*4f1223e8SApple OSS Distributions static void
main_test(void)50*4f1223e8SApple OSS Distributions main_test(void)
51*4f1223e8SApple OSS Distributions {
52*4f1223e8SApple OSS Distributions 	int ret;
53*4f1223e8SApple OSS Distributions 	mach_port_name_t task_name;
54*4f1223e8SApple OSS Distributions 	vmobject_list_output_t out_buffer;
55*4f1223e8SApple OSS Distributions 	size_t out_size;
56*4f1223e8SApple OSS Distributions 	size_t output_size;
57*4f1223e8SApple OSS Distributions 	const vm_size_t tmp_size = 16 * 1024 * 1024; /* arbitrary size */
58*4f1223e8SApple OSS Distributions 	vm_address_t tmp_buf;
59*4f1223e8SApple OSS Distributions 	vm_address_t tmp_buf2;
60*4f1223e8SApple OSS Distributions 	mach_vm_size_t addr_size;
61*4f1223e8SApple OSS Distributions 	mach_vm_address_t addr;
62*4f1223e8SApple OSS Distributions 	kern_return_t kr;
63*4f1223e8SApple OSS Distributions 	mach_port_t __self = mach_task_self();
64*4f1223e8SApple OSS Distributions 	vm_region_submap_info_data_64_t regionInfo;
65*4f1223e8SApple OSS Distributions 	uint32_t nestingDepth;
66*4f1223e8SApple OSS Distributions 	mach_msg_type_number_t count;
67*4f1223e8SApple OSS Distributions 
68*4f1223e8SApple OSS Distributions 	/* allocate a temporary buffer */
69*4f1223e8SApple OSS Distributions 	kr = vm_allocate(__self, &tmp_buf, tmp_size, VM_FLAGS_ANYWHERE | VM_FLAGS_PURGABLE);
70*4f1223e8SApple OSS Distributions 	T_QUIET;
71*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_allocate(%zu) error 0x%x (%s)",
72*4f1223e8SApple OSS Distributions 	    (size_t) tmp_size, kr, mach_error_string(kr));
73*4f1223e8SApple OSS Distributions 	T_QUIET;
74*4f1223e8SApple OSS Distributions 	T_EXPECT_NE(tmp_buf, (vm_address_t) 0, "failed to allocate temporary purgable buffer\n");
75*4f1223e8SApple OSS Distributions 
76*4f1223e8SApple OSS Distributions 	kr = vm_allocate(__self, &tmp_buf2, tmp_size, VM_FLAGS_ANYWHERE | VM_FLAGS_PURGABLE);
77*4f1223e8SApple OSS Distributions 	T_QUIET;
78*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_allocate(%zu) error 0x%x (%s)",
79*4f1223e8SApple OSS Distributions 	    (size_t) tmp_size, kr, mach_error_string(kr));
80*4f1223e8SApple OSS Distributions 	T_QUIET;
81*4f1223e8SApple OSS Distributions 	T_EXPECT_NE(tmp_buf2, (vm_address_t) 0, "failed to allocate temporary purgable buffer\n");
82*4f1223e8SApple OSS Distributions 
83*4f1223e8SApple OSS Distributions 	/* expected failures */
84*4f1223e8SApple OSS Distributions 	out_size = tmp_size;
85*4f1223e8SApple OSS Distributions 	ret = sysctlbyname(g_sysctl_name, NULL, 0, NULL, 0);
86*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(ret, -1, "expected failure with 0 parameters\n");
87*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(errno, EINVAL, "expected EINVAL with 0 parameters\n");
88*4f1223e8SApple OSS Distributions 
89*4f1223e8SApple OSS Distributions 	ret = sysctlbyname(g_sysctl_name, (void*) tmp_buf, &out_size, NULL, 0);
90*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(ret, -1, "expected failure with no new parameters\n");
91*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(errno, EINVAL, "expected EINVAL with 0 new parameters\n");
92*4f1223e8SApple OSS Distributions 
93*4f1223e8SApple OSS Distributions 	out_size = tmp_size;
94*4f1223e8SApple OSS Distributions 	ret = sysctlbyname(g_sysctl_name, NULL, 0, (void*) tmp_buf, out_size);
95*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(ret, -1, "expected failure with no old parameters\n");
96*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(errno, EINVAL, "expected EINVAL with 0 old parameters\n");
97*4f1223e8SApple OSS Distributions 
98*4f1223e8SApple OSS Distributions 	task_name = MACH_PORT_NULL;
99*4f1223e8SApple OSS Distributions 	ret = sysctlbyname(g_sysctl_name, (void*) tmp_buf, &out_size, &task_name, sizeof(task_name));
100*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(ret, -1, "expected failure with task_name == MACH_PORT_NULL in new parameters\n");
101*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(errno, ESRCH, "expected ESRCH with invalid task port name\n");
102*4f1223e8SApple OSS Distributions 
103*4f1223e8SApple OSS Distributions 	out_size = 0;
104*4f1223e8SApple OSS Distributions 	task_name = __self;
105*4f1223e8SApple OSS Distributions 	ret = sysctlbyname(g_sysctl_name, (void*) tmp_buf, &out_size, &task_name, sizeof(task_name));
106*4f1223e8SApple OSS Distributions 	T_QUIET;
107*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(ret, -1, "expected failure with out_size == 0\n");
108*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(errno, EINVAL, "expected EINVAL with 0 output size and valid pointer\n");
109*4f1223e8SApple OSS Distributions 
110*4f1223e8SApple OSS Distributions 	/* we should get the number of entries we should allocate for */
111*4f1223e8SApple OSS Distributions 	out_size = 0;
112*4f1223e8SApple OSS Distributions 	output_size = 0;
113*4f1223e8SApple OSS Distributions 	ret = sysctlbyname(g_sysctl_name, NULL, &out_size, &task_name, sizeof(task_name));
114*4f1223e8SApple OSS Distributions 	T_QUIET;
115*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(ret, 0, "failed getting the number of entries\n");
116*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(out_size, 2 * sizeof(vm_object_query_data_t) + sizeof(int64_t), "expected one entry\n");
117*4f1223e8SApple OSS Distributions 
118*4f1223e8SApple OSS Distributions 	/* calculcate and allocate the proper sized output buffer */
119*4f1223e8SApple OSS Distributions 	output_size = out_size;
120*4f1223e8SApple OSS Distributions 	out_buffer = (vmobject_list_output_t)calloc(output_size, 1);
121*4f1223e8SApple OSS Distributions 	T_QUIET;
122*4f1223e8SApple OSS Distributions 	T_EXPECT_NE(out_buffer, NULL, "failed to allocate the output buffer for sysctlbyname\n");
123*4f1223e8SApple OSS Distributions 
124*4f1223e8SApple OSS Distributions 	/* get the truncated list for the current process */
125*4f1223e8SApple OSS Distributions 	memset(out_buffer, 0, output_size);
126*4f1223e8SApple OSS Distributions 	out_size = 1 * sizeof(vm_object_query_data_t) + sizeof(int64_t);
127*4f1223e8SApple OSS Distributions 	ret = sysctlbyname(g_sysctl_name, out_buffer, &out_size, &task_name, sizeof(task_name));
128*4f1223e8SApple OSS Distributions 
129*4f1223e8SApple OSS Distributions 	T_QUIET;
130*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(ret, 0, "sysctlbyname failed\n");
131*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(out_size, 1 * sizeof(vm_object_query_data_t) + sizeof(int64_t), "sysctl return size is incorrect\n");
132*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(out_buffer->entries, 1ULL, "should have 1 vm object\n");
133*4f1223e8SApple OSS Distributions 	T_EXPECT_NE(out_buffer->data[0].object_id, 0ULL, "vm_object_id should not be 0\n");
134*4f1223e8SApple OSS Distributions 
135*4f1223e8SApple OSS Distributions 	/* get the list for the current process with an overly large size */
136*4f1223e8SApple OSS Distributions 	out_size = SIZE_MAX;
137*4f1223e8SApple OSS Distributions 	memset(out_buffer, 0, output_size);
138*4f1223e8SApple OSS Distributions 	ret = sysctlbyname(g_sysctl_name, out_buffer, &out_size, &task_name, sizeof(task_name));
139*4f1223e8SApple OSS Distributions 
140*4f1223e8SApple OSS Distributions 	T_QUIET;
141*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(ret, 0, "sysctlbyname failed\n");
142*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(out_size, 2 * sizeof(vm_object_query_data_t) + sizeof(int64_t), "sysctl return size is incorrect\n");
143*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(out_buffer->entries, 2ULL, "should have 2 vm objects\n");
144*4f1223e8SApple OSS Distributions 	T_EXPECT_NE(out_buffer->data[0].object_id, 0ULL, "vm_object_id should not be 0\n");
145*4f1223e8SApple OSS Distributions 
146*4f1223e8SApple OSS Distributions 	/* get the list for the current process with the correct output size */
147*4f1223e8SApple OSS Distributions 	out_size = output_size;
148*4f1223e8SApple OSS Distributions 	memset(out_buffer, 0, output_size);
149*4f1223e8SApple OSS Distributions 	ret = sysctlbyname(g_sysctl_name, out_buffer, &out_size, &task_name, sizeof(task_name));
150*4f1223e8SApple OSS Distributions 
151*4f1223e8SApple OSS Distributions 	T_QUIET;
152*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(ret, 0, "sysctlbyname failed\n");
153*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(out_size, 2 * sizeof(vm_object_query_data_t) + sizeof(int64_t), "sysctl return size is incorrect\n");
154*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(out_buffer->entries, 2ULL, "should have 2 vm objects\n");
155*4f1223e8SApple OSS Distributions 	T_EXPECT_NE(out_buffer->data[0].object_id, 0ULL, "vm_object_id should not be 0\n");
156*4f1223e8SApple OSS Distributions 
157*4f1223e8SApple OSS Distributions 	addr = tmp_buf;
158*4f1223e8SApple OSS Distributions 	addr_size = tmp_size;
159*4f1223e8SApple OSS Distributions 	nestingDepth = UINT_MAX;
160*4f1223e8SApple OSS Distributions 	count = VM_REGION_SUBMAP_INFO_V2_COUNT_64;
161*4f1223e8SApple OSS Distributions 	kr = mach_vm_region_recurse(__self, &addr, &addr_size, &nestingDepth, (vm_region_info_t)&regionInfo, &count);
162*4f1223e8SApple OSS Distributions 	T_QUIET;
163*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "mach_vm_region_recurse(%zu) error 0x%x (%s)\n",
164*4f1223e8SApple OSS Distributions 	    tmp_size, kr, mach_error_string(kr));
165*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(regionInfo.object_id_full, out_buffer->data[0].object_id, "object_id_full does not match out_buffer->object[0]\n");
166*4f1223e8SApple OSS Distributions 
167*4f1223e8SApple OSS Distributions 	addr = tmp_buf2;
168*4f1223e8SApple OSS Distributions 	addr_size = tmp_size;
169*4f1223e8SApple OSS Distributions 	nestingDepth = UINT_MAX;
170*4f1223e8SApple OSS Distributions 	count = VM_REGION_SUBMAP_INFO_V2_COUNT_64;
171*4f1223e8SApple OSS Distributions 	kr = mach_vm_region_recurse(__self, &addr, &addr_size, &nestingDepth, (vm_region_info_t)&regionInfo, &count);
172*4f1223e8SApple OSS Distributions 	T_QUIET;
173*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "mach_vm_region_recurse(%zu) error 0x%x (%s)\n",
174*4f1223e8SApple OSS Distributions 	    tmp_size, kr, mach_error_string(kr));
175*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(regionInfo.object_id_full, out_buffer->data[1].object_id, "object_id_full does not match out_buffer->object[1]\n");
176*4f1223e8SApple OSS Distributions 
177*4f1223e8SApple OSS Distributions 	/* corpse */
178*4f1223e8SApple OSS Distributions 	{
179*4f1223e8SApple OSS Distributions 		mach_port_t corpse_port = get_corpse();
180*4f1223e8SApple OSS Distributions 
181*4f1223e8SApple OSS Distributions 		/* corpse_port can be a valid NULL if out of resources, corpse limit, or corpses disabled */
182*4f1223e8SApple OSS Distributions 		if (corpse_port != MACH_PORT_NULL) {
183*4f1223e8SApple OSS Distributions 			vmobject_list_output_t corpse_out_buffer;
184*4f1223e8SApple OSS Distributions 			size_t corpse_out_size;
185*4f1223e8SApple OSS Distributions 			size_t corpse_output_size;
186*4f1223e8SApple OSS Distributions 
187*4f1223e8SApple OSS Distributions 			/* we should get the number of entries we should allocate for */
188*4f1223e8SApple OSS Distributions 			corpse_out_size = 0;
189*4f1223e8SApple OSS Distributions 			ret = sysctlbyname(g_sysctl_name, NULL, &corpse_out_size, &corpse_port, sizeof(corpse_port));
190*4f1223e8SApple OSS Distributions 
191*4f1223e8SApple OSS Distributions 			T_QUIET;
192*4f1223e8SApple OSS Distributions 			T_EXPECT_EQ(ret, 0, "failed getting the number of entries for corpse\n");
193*4f1223e8SApple OSS Distributions 			T_EXPECT_EQ(corpse_out_size, out_size, "corpse output size matchrd the parent process\n");
194*4f1223e8SApple OSS Distributions 			T_EXPECT_EQ(corpse_out_size, 2 * sizeof(vm_object_query_data_t) + sizeof(int64_t), "corpse expected one entry\n");
195*4f1223e8SApple OSS Distributions 
196*4f1223e8SApple OSS Distributions 			/* calculcate and allocate the proper sized output buffer */
197*4f1223e8SApple OSS Distributions 			corpse_output_size = corpse_out_size;
198*4f1223e8SApple OSS Distributions 			corpse_out_buffer = (vmobject_list_output_t)calloc(corpse_output_size, 1);
199*4f1223e8SApple OSS Distributions 			T_QUIET;
200*4f1223e8SApple OSS Distributions 			T_EXPECT_NE(corpse_out_buffer, NULL, "failed to allocate the output buffer for sysctlbyname for corpse\n");
201*4f1223e8SApple OSS Distributions 
202*4f1223e8SApple OSS Distributions 			/* get the list for the current process */
203*4f1223e8SApple OSS Distributions 			corpse_out_size = corpse_output_size;
204*4f1223e8SApple OSS Distributions 			memset(corpse_out_buffer, 0, corpse_output_size);
205*4f1223e8SApple OSS Distributions 			ret = sysctlbyname(g_sysctl_name, corpse_out_buffer, &corpse_out_size, &corpse_port, sizeof(corpse_port));
206*4f1223e8SApple OSS Distributions 
207*4f1223e8SApple OSS Distributions 			int rc = memcmp(corpse_out_buffer, out_buffer, corpse_out_size);
208*4f1223e8SApple OSS Distributions 
209*4f1223e8SApple OSS Distributions 			T_QUIET;
210*4f1223e8SApple OSS Distributions 			T_EXPECT_EQ(ret, 0, "corpse sysctlbyname failed\n");
211*4f1223e8SApple OSS Distributions 			T_EXPECT_EQ(rc, 0, "corpse vmobjects should match parent vmobjects\n");
212*4f1223e8SApple OSS Distributions 			T_EXPECT_EQ(corpse_out_size, 2 * sizeof(vm_object_query_data_t) + sizeof(int64_t), "corpse sysctl return size is incorrect\n");
213*4f1223e8SApple OSS Distributions 			T_EXPECT_EQ(corpse_out_buffer->entries, 2ULL, "corpse should have 2 vm objects\n");
214*4f1223e8SApple OSS Distributions 			T_EXPECT_NE(corpse_out_buffer->data[0].object_id, 0ULL, "corpse vm_object_id should not be 0\n");
215*4f1223e8SApple OSS Distributions 
216*4f1223e8SApple OSS Distributions 			free(corpse_out_buffer);
217*4f1223e8SApple OSS Distributions 			mach_port_deallocate(mach_task_self(), corpse_port);
218*4f1223e8SApple OSS Distributions 		}
219*4f1223e8SApple OSS Distributions 	}
220*4f1223e8SApple OSS Distributions 
221*4f1223e8SApple OSS Distributions 	kr = vm_deallocate(__self, tmp_buf, tmp_size);
222*4f1223e8SApple OSS Distributions 	T_QUIET;
223*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_deallocate(%zu) error 0x%x (%s)\n",
224*4f1223e8SApple OSS Distributions 	    tmp_size, kr, mach_error_string(kr));
225*4f1223e8SApple OSS Distributions 
226*4f1223e8SApple OSS Distributions 	kr = vm_deallocate(__self, tmp_buf2, tmp_size);
227*4f1223e8SApple OSS Distributions 	T_QUIET;
228*4f1223e8SApple OSS Distributions 	T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_deallocate(%zu) error 0x%x (%s)\n",
229*4f1223e8SApple OSS Distributions 	    tmp_size, kr, mach_error_string(kr));
230*4f1223e8SApple OSS Distributions 
231*4f1223e8SApple OSS Distributions 	free(out_buffer);
232*4f1223e8SApple OSS Distributions 	out_buffer = NULL;
233*4f1223e8SApple OSS Distributions }
234*4f1223e8SApple OSS Distributions 
235*4f1223e8SApple OSS Distributions T_DECL(test_get_vmobject_list, "Get owned vm_objects for process", T_META_TAG_VM_PREFERRED)
236*4f1223e8SApple OSS Distributions {
237*4f1223e8SApple OSS Distributions 	main_test();
238*4f1223e8SApple OSS Distributions }
239