]>
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 A |
25 | static mach_port_t |
26 | get_atm_voucher(void) | |
eee35659 A |
27 | { |
28 | mach_voucher_attr_recipe_data_t r = { | |
29 | .key = MACH_VOUCHER_ATTR_KEY_ATM, | |
30 | .command = MACH_VOUCHER_ATTR_ATM_CREATE | |
31 | }; | |
32 | mach_port_t port = MACH_PORT_NULL; | |
33 | kern_return_t kr = host_create_mach_voucher(mach_host_self(), | |
0a7de745 A |
34 | (mach_voucher_attr_raw_recipe_array_t)&r, |
35 | sizeof(r), &port); | |
eee35659 A |
36 | T_ASSERT_MACH_SUCCESS(kr, "Create ATM voucher: 0x%x", (unsigned int)port); |
37 | ||
38 | return port; | |
39 | } | |
40 | ||
41 | ||
42 | T_DECL(voucher_extract_attr_recipe, "voucher_extract_attr_recipe") | |
43 | { | |
44 | kern_return_t kr; | |
45 | mach_vm_size_t alloc_sz; | |
46 | mach_port_t port; | |
47 | mach_vm_address_t alloc_addr; | |
48 | ||
49 | /* map at least a page of memory at some arbitrary location */ | |
50 | alloc_sz = (mach_vm_size_t)round_page(MACH_VOUCHER_TRAP_STACK_LIMIT + 1); | |
51 | ||
52 | /* | |
53 | * We could theoretically ask for a fixed location, but this is more | |
54 | * reliable, and we're not actually trying to exploit anything - a | |
55 | * kernel panic on failure should suffice :-) | |
56 | */ | |
57 | alloc_addr = (mach_vm_address_t)round_page(MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE + 1); | |
58 | kr = mach_vm_allocate(mach_task_self(), &alloc_addr, | |
0a7de745 | 59 | alloc_sz, VM_FLAGS_ANYWHERE); |
eee35659 A |
60 | |
61 | /* | |
62 | * Make sure that the address of the allocation is larger than the | |
63 | * maximum recipe size: this will test for the bug that was fixed in | |
64 | * <rdar://problem/29379175>. | |
65 | */ | |
66 | T_ASSERT_GT_ULLONG((uint64_t)alloc_addr, | |
0a7de745 A |
67 | (uint64_t)MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE, |
68 | "Recipe addr (%llu bytes): 0x%llx > max recipe sz: %llu", | |
69 | (uint64_t)alloc_sz, (uint64_t)alloc_addr, | |
70 | (uint64_t)MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE); | |
eee35659 A |
71 | |
72 | /* make the allocation look like a pointer to an int */ | |
73 | mach_msg_type_number_t *recipe_size; | |
74 | recipe_size = (mach_msg_type_number_t *)((uintptr_t)alloc_addr); | |
75 | bzero(recipe_size, (unsigned long)alloc_sz); | |
0a7de745 | 76 | if (alloc_sz > MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE) { |
eee35659 | 77 | *recipe_size = MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE; |
0a7de745 | 78 | } else { |
eee35659 | 79 | *recipe_size = (mach_msg_type_number_t)alloc_sz; |
0a7de745 | 80 | } |
eee35659 A |
81 | |
82 | /* recipe buffer on the heap: memset it so panics show up loudly */ | |
83 | size_t size = (size_t)(10 * 1024 * 1024); | |
84 | void *recipe = malloc(size); | |
85 | memset(recipe, 0x41, size); | |
86 | ||
87 | port = get_atm_voucher(); | |
88 | ||
89 | /* | |
90 | * This should try to extract the ATM attribute using a buffer on the | |
91 | * kernel heap (probably zone memory). | |
92 | */ | |
93 | kr = mach_voucher_extract_attr_recipe_trap(port, MACH_VOUCHER_ATTR_KEY_ATM, | |
0a7de745 | 94 | recipe, recipe_size); |
eee35659 A |
95 | T_ASSERT_MACH_SUCCESS(kr, "Extract attribute data with recipe: heap"); |
96 | ||
97 | /* reset the recipe memory */ | |
98 | memset(recipe, 0x41, size); | |
99 | /* reduce the size to get an allocation on the kernel stack */ | |
100 | *recipe_size = MACH_VOUCHER_TRAP_STACK_LIMIT - 1; | |
101 | ||
102 | /* | |
103 | * This should try to extract the ATM attribute using a buffer on the | |
104 | * kernel stack. | |
105 | */ | |
106 | kr = mach_voucher_extract_attr_recipe_trap(port, MACH_VOUCHER_ATTR_KEY_ATM, | |
0a7de745 | 107 | recipe, recipe_size); |
eee35659 A |
108 | T_ASSERT_MACH_SUCCESS(kr, "Extract attribute data with recipe: stack"); |
109 | ||
110 | /* cleanup */ | |
111 | ||
112 | free(recipe); | |
113 | kr = mach_vm_deallocate(mach_task_self(), alloc_addr, alloc_sz); | |
114 | T_ASSERT_MACH_SUCCESS(kr, "Deallocate recipe buffers"); | |
115 | } |