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