xref: /xnu-11417.101.15/tests/voucher_traps.c (revision e3723e1f17661b24996789d8afc084c0c3303b26)
1*e3723e1fSApple OSS Distributions /*
2*e3723e1fSApple OSS Distributions  * Test voucher trap APIs.
3*e3723e1fSApple OSS Distributions  * There was an unfortunate bug in the trap interface that used the user space
4*e3723e1fSApple OSS Distributions  * _address_ of a trap parameter as a copyin size. This test validates there
5*e3723e1fSApple OSS Distributions  * are no other kernel panics in the voucher create and voucher attribute
6*e3723e1fSApple OSS Distributions  * extraction mach traps.
7*e3723e1fSApple OSS Distributions  *
8*e3723e1fSApple OSS Distributions  * clang -o voucher_traps voucher_traps.c -ldarwintest -Weverything -Wno-gnu-flexible-array-initializer
9*e3723e1fSApple OSS Distributions  *
10*e3723e1fSApple OSS Distributions  * <rdar://problem/29379175>
11*e3723e1fSApple OSS Distributions  */
12*e3723e1fSApple OSS Distributions 
13*e3723e1fSApple OSS Distributions #include <stdint.h>
14*e3723e1fSApple OSS Distributions #include <stdlib.h>
15*e3723e1fSApple OSS Distributions #include <mach/mach.h>
16*e3723e1fSApple OSS Distributions #include <mach/mach_vm.h>
17*e3723e1fSApple OSS Distributions #include <mach/mach_traps.h>
18*e3723e1fSApple OSS Distributions 
19*e3723e1fSApple OSS Distributions #include <atm/atm_types.h>
20*e3723e1fSApple OSS Distributions 
21*e3723e1fSApple OSS Distributions #include <darwintest.h>
22*e3723e1fSApple OSS Distributions 
23*e3723e1fSApple OSS Distributions T_GLOBAL_META(
24*e3723e1fSApple OSS Distributions 	T_META_NAMESPACE("xnu.ipc"),
25*e3723e1fSApple OSS Distributions 	T_META_RUN_CONCURRENTLY(TRUE),
26*e3723e1fSApple OSS Distributions 	T_META_RADAR_COMPONENT_NAME("xnu"),
27*e3723e1fSApple OSS Distributions 	T_META_RADAR_COMPONENT_VERSION("IPC"));
28*e3723e1fSApple OSS Distributions 
29*e3723e1fSApple OSS Distributions static mach_port_t
get_user_data_port(mach_msg_type_number_t * size)30*e3723e1fSApple OSS Distributions get_user_data_port(mach_msg_type_number_t *size)
31*e3723e1fSApple OSS Distributions {
32*e3723e1fSApple OSS Distributions #define DATA "Hello World!"
33*e3723e1fSApple OSS Distributions 	struct {
34*e3723e1fSApple OSS Distributions 		mach_voucher_attr_recipe_data_t recipe;
35*e3723e1fSApple OSS Distributions 		char data[sizeof(DATA)];
36*e3723e1fSApple OSS Distributions 	} buf = {
37*e3723e1fSApple OSS Distributions 		.recipe = {
38*e3723e1fSApple OSS Distributions 			.key     = MACH_VOUCHER_ATTR_KEY_USER_DATA,
39*e3723e1fSApple OSS Distributions 			.command = MACH_VOUCHER_ATTR_USER_DATA_STORE,
40*e3723e1fSApple OSS Distributions 			.content_size = sizeof(DATA),
41*e3723e1fSApple OSS Distributions 		},
42*e3723e1fSApple OSS Distributions 		.data = DATA,
43*e3723e1fSApple OSS Distributions 	};
44*e3723e1fSApple OSS Distributions 
45*e3723e1fSApple OSS Distributions 	mach_port_t port = MACH_PORT_NULL;
46*e3723e1fSApple OSS Distributions 	kern_return_t kr = host_create_mach_voucher(mach_host_self(),
47*e3723e1fSApple OSS Distributions 	    (mach_voucher_attr_raw_recipe_array_t)&buf,
48*e3723e1fSApple OSS Distributions 	    sizeof(buf), &port);
49*e3723e1fSApple OSS Distributions #if !TARGET_OS_OSX
50*e3723e1fSApple OSS Distributions 	T_ASSERT_NE(kr, KERN_SUCCESS, "User data manager removed on embedded");
51*e3723e1fSApple OSS Distributions 	T_END;
52*e3723e1fSApple OSS Distributions #endif
53*e3723e1fSApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(kr, "Create USER_DATA voucher: 0x%x",
54*e3723e1fSApple OSS Distributions 	    (unsigned int)port);
55*e3723e1fSApple OSS Distributions 
56*e3723e1fSApple OSS Distributions 	if (size) {
57*e3723e1fSApple OSS Distributions 		*size = sizeof(buf);
58*e3723e1fSApple OSS Distributions 	}
59*e3723e1fSApple OSS Distributions 	return port;
60*e3723e1fSApple OSS Distributions }
61*e3723e1fSApple OSS Distributions 
62*e3723e1fSApple OSS Distributions 
63*e3723e1fSApple OSS Distributions T_DECL(voucher_extract_attr_recipe, "voucher_extract_attr_recipe", T_META_TAG_VM_PREFERRED)
64*e3723e1fSApple OSS Distributions {
65*e3723e1fSApple OSS Distributions 	kern_return_t kr;
66*e3723e1fSApple OSS Distributions 	mach_vm_size_t alloc_sz;
67*e3723e1fSApple OSS Distributions 	mach_port_t port;
68*e3723e1fSApple OSS Distributions 	mach_vm_address_t alloc_addr;
69*e3723e1fSApple OSS Distributions 	mach_msg_type_number_t expected_size;
70*e3723e1fSApple OSS Distributions 
71*e3723e1fSApple OSS Distributions 	/* map at least a page of memory at some arbitrary location */
72*e3723e1fSApple OSS Distributions 	alloc_sz = (mach_vm_size_t)round_page(MACH_VOUCHER_TRAP_STACK_LIMIT + 1);
73*e3723e1fSApple OSS Distributions 
74*e3723e1fSApple OSS Distributions 	/*
75*e3723e1fSApple OSS Distributions 	 * We could theoretically ask for a fixed location, but this is more
76*e3723e1fSApple OSS Distributions 	 * reliable, and we're not actually trying to exploit anything - a
77*e3723e1fSApple OSS Distributions 	 * kernel panic on failure should suffice :-)
78*e3723e1fSApple OSS Distributions 	 */
79*e3723e1fSApple OSS Distributions 	alloc_addr = (mach_vm_address_t)round_page(MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE + 1);
80*e3723e1fSApple OSS Distributions 	kr = mach_vm_allocate(mach_task_self(), &alloc_addr,
81*e3723e1fSApple OSS Distributions 	    alloc_sz, VM_FLAGS_ANYWHERE);
82*e3723e1fSApple OSS Distributions 
83*e3723e1fSApple OSS Distributions 	/*
84*e3723e1fSApple OSS Distributions 	 * Make sure that the address of the allocation is larger than the
85*e3723e1fSApple OSS Distributions 	 * maximum recipe size: this will test for the bug that was fixed in
86*e3723e1fSApple OSS Distributions 	 * <rdar://problem/29379175>.
87*e3723e1fSApple OSS Distributions 	 */
88*e3723e1fSApple OSS Distributions 	T_ASSERT_GT_ULLONG((uint64_t)alloc_addr,
89*e3723e1fSApple OSS Distributions 	    (uint64_t)MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE,
90*e3723e1fSApple OSS Distributions 	    "Recipe addr (%llu bytes): 0x%llx > max recipe sz: %llu",
91*e3723e1fSApple OSS Distributions 	    (uint64_t)alloc_sz, (uint64_t)alloc_addr,
92*e3723e1fSApple OSS Distributions 	    (uint64_t)MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE);
93*e3723e1fSApple OSS Distributions 
94*e3723e1fSApple OSS Distributions 	/* make the allocation look like a pointer to an int */
95*e3723e1fSApple OSS Distributions 	mach_msg_type_number_t *recipe_size;
96*e3723e1fSApple OSS Distributions 	recipe_size = (mach_msg_type_number_t *)((uintptr_t)alloc_addr);
97*e3723e1fSApple OSS Distributions 	bzero(recipe_size, (unsigned long)alloc_sz);
98*e3723e1fSApple OSS Distributions 	if (alloc_sz > MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE) {
99*e3723e1fSApple OSS Distributions 		*recipe_size = MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE;
100*e3723e1fSApple OSS Distributions 	} else {
101*e3723e1fSApple OSS Distributions 		*recipe_size = (mach_msg_type_number_t)alloc_sz;
102*e3723e1fSApple OSS Distributions 	}
103*e3723e1fSApple OSS Distributions 
104*e3723e1fSApple OSS Distributions 	/* recipe buffer on the heap: memset it so panics show up loudly */
105*e3723e1fSApple OSS Distributions 	size_t size = (size_t)(10 * 1024 * 1024);
106*e3723e1fSApple OSS Distributions 	void *recipe = malloc(size);
107*e3723e1fSApple OSS Distributions 	memset(recipe, 0x41, size);
108*e3723e1fSApple OSS Distributions 
109*e3723e1fSApple OSS Distributions 	port = get_user_data_port(&expected_size);
110*e3723e1fSApple OSS Distributions 
111*e3723e1fSApple OSS Distributions 	/*
112*e3723e1fSApple OSS Distributions 	 * This should try to extract the USER_DATA attribute using a buffer on the
113*e3723e1fSApple OSS Distributions 	 * kernel heap (probably zone memory).
114*e3723e1fSApple OSS Distributions 	 */
115*e3723e1fSApple OSS Distributions 	kr = mach_voucher_extract_attr_recipe_trap(port,
116*e3723e1fSApple OSS Distributions 	    MACH_VOUCHER_ATTR_KEY_USER_DATA, recipe, recipe_size);
117*e3723e1fSApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(kr, "Extract attribute data with recipe: heap");
118*e3723e1fSApple OSS Distributions 	T_ASSERT_EQ(*recipe_size, expected_size, "size should match");
119*e3723e1fSApple OSS Distributions 
120*e3723e1fSApple OSS Distributions 	/* reset the recipe memory */
121*e3723e1fSApple OSS Distributions 	memset(recipe, 0x41, size);
122*e3723e1fSApple OSS Distributions 	/* reduce the size to get an allocation on the kernel stack */
123*e3723e1fSApple OSS Distributions 	*recipe_size = MACH_VOUCHER_TRAP_STACK_LIMIT - 1;
124*e3723e1fSApple OSS Distributions 
125*e3723e1fSApple OSS Distributions 	/*
126*e3723e1fSApple OSS Distributions 	 * This should try to extract the USER_DATA attribute using a buffer on the
127*e3723e1fSApple OSS Distributions 	 * kernel stack.
128*e3723e1fSApple OSS Distributions 	 */
129*e3723e1fSApple OSS Distributions 	kr = mach_voucher_extract_attr_recipe_trap(port,
130*e3723e1fSApple OSS Distributions 	    MACH_VOUCHER_ATTR_KEY_USER_DATA, recipe, recipe_size);
131*e3723e1fSApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(kr, "Extract attribute data with recipe: stack");
132*e3723e1fSApple OSS Distributions 	T_ASSERT_EQ(*recipe_size, expected_size, "size should match");
133*e3723e1fSApple OSS Distributions 
134*e3723e1fSApple OSS Distributions 	/* cleanup */
135*e3723e1fSApple OSS Distributions 
136*e3723e1fSApple OSS Distributions 	free(recipe);
137*e3723e1fSApple OSS Distributions 	kr = mach_vm_deallocate(mach_task_self(), alloc_addr, alloc_sz);
138*e3723e1fSApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(kr, "Deallocate recipe buffers");
139*e3723e1fSApple OSS Distributions }
140