1 #include <darwintest.h>
2
3 #include <stdlib.h>
4
5 #include <mach/mach_host.h>
6 #include <mach/mach_init.h>
7 #include <mach/mach_vm.h>
8 #include <mach/vm_map.h>
9
10 T_GLOBAL_META(
11 T_META_NAMESPACE("xnu.vm"),
12 T_META_RADAR_COMPONENT_NAME("xnu"),
13 T_META_RADAR_COMPONENT_VERSION("VM"));
14
15 void
test_90774260(void)16 test_90774260(void)
17 {
18 kern_return_t kr;
19 mach_vm_size_t vm_size = 1024 * 1024;
20 int fail = 0;
21 int original_value;
22
23 uint64_t first_layer_addr = 0;
24 mach_port_t first_layer_entry_port = 0;
25 kr = mach_memory_object_memory_entry(mach_host_self(),
26 1, (vm_size_t) vm_size,
27 VM_PROT_READ | VM_PROT_WRITE,
28 0, &first_layer_entry_port);
29 if (kr == MIG_BAD_ID) {
30 T_FAIL("mach_memory_object_memory_entry() returned MIG_BAD_ID");
31 return;
32 }
33 #if __arm64__ && !__LP64__
34 /*
35 * mach_memory_object_memory_entry() is broken on arm64_32.
36 * Use mach_make_memory_entry_64(MAP_MEM_NAMED_CREATE) instead.
37 */
38 if (kr == MIG_BAD_ARGUMENTS) {
39 T_LOG("mach_memory_object_memory_entry() returned MIG_BAD_ARGUMENTS (because broken on arm64_32)");
40
41 memory_object_size_t me_size = vm_size;
42 kr = mach_make_memory_entry_64(mach_task_self(),
43 &me_size,
44 0,
45 VM_PROT_READ | VM_PROT_WRITE | MAP_MEM_NAMED_CREATE,
46 &first_layer_entry_port,
47 MACH_PORT_NULL);
48 T_ASSERT_MACH_SUCCESS(kr, "mach_make_memory_entry_64(MAP_MEM_NAMED_CREATE)");
49 } else
50 #endif /* __arm64__ && !__LP64__ */
51 {
52 T_ASSERT_MACH_SUCCESS(kr, "mach_memory_object_memory_entry()");
53 }
54
55 // map the memory to our space
56 kr = mach_vm_map(mach_task_self(),
57 &first_layer_addr,
58 vm_size,
59 0, /* mask */
60 VM_FLAGS_ANYWHERE,
61 first_layer_entry_port,
62 0, /* offset */
63 0, /* copy */
64 VM_PROT_READ | VM_PROT_WRITE,
65 VM_PROT_READ | VM_PROT_WRITE,
66 VM_INHERIT_DEFAULT);
67 T_ASSERT_MACH_SUCCESS(kr, "mach_vm_map(first_layer_addr)");
68
69 original_value = 0xabcd;
70 *(int*)first_layer_addr = original_value;
71
72 // create a COW port
73 mach_port_t cow_port = MACH_PORT_NULL;
74 mach_vm_size_t me_size = vm_size;
75 kr = mach_make_memory_entry_64(mach_task_self(),
76 &me_size,
77 first_layer_addr,
78 (VM_PROT_READ | VM_PROT_WRITE | MAP_MEM_VM_COPY),
79 &cow_port,
80 0);
81 T_ASSERT_MACH_SUCCESS(kr, "mach_make_memory_entry_64()");
82 T_QUIET; T_ASSERT_EQ(me_size, vm_size, "incomplete memory entry");
83
84 // map cow port to a new address in the shared way
85 uint64_t shared_addr = 0;
86 kr = mach_vm_map(mach_task_self(),
87 &shared_addr,
88 vm_size,
89 0, /* mask */
90 VM_FLAGS_ANYWHERE,
91 cow_port,
92 0, /* offset */
93 0, /* copy */
94 VM_PROT_READ | VM_PROT_WRITE,
95 VM_PROT_READ | VM_PROT_WRITE,
96 VM_INHERIT_DEFAULT);
97 T_ASSERT_MACH_SUCCESS(kr, "mach_vm_map(shared_addr)");
98
99 // map cow port to a new address in the COW way
100 uint64_t cow_addr = 0;
101 kr = mach_vm_map(mach_task_self(),
102 &cow_addr,
103 vm_size,
104 0, /* mask */
105 VM_FLAGS_ANYWHERE,
106 cow_port,
107 0, /* offset */
108 1, /* copy */
109 VM_PROT_READ | VM_PROT_WRITE,
110 VM_PROT_READ | VM_PROT_WRITE,
111 VM_INHERIT_DEFAULT);
112 T_ASSERT_MACH_SUCCESS(kr, "mach_vm_map(cow_addr)");
113
114 // T_LOG("first_layer_addr = 0x%llx", first_layer_addr);
115 // T_LOG("shared_addr = 0x%llx\n", shared_addr);
116 // T_LOG("cow_addr = 0x%llx\n", cow_addr);
117
118 // T_LOG("*(int*)first_layer_addr = 0x%x", *(int*)first_layer_addr);
119 // T_LOG("*(int*)shared_addr = 0x%x\n", *(int*)shared_addr);
120 // T_LOG("*(int*)shared_addr2 = 0x%x\n", *(int*)shared_addr2);
121 // T_LOG("*(int*)cow_addr = 0x%x\n", *(int*)cow_addr);
122
123 T_LOG("write 0x%x to *(int*)shared_addr", 0x1234);
124 *(int*)shared_addr = 0x1234;
125
126 T_LOG("*(int*)first_layer_addr = 0x%x", *(int*)first_layer_addr);
127 T_LOG("*(int*)shared_addr = 0x%x\n", *(int*)shared_addr);
128 T_LOG("*(int*)cow_addr = 0x%x\n", *(int*)cow_addr);
129
130 if (*(int*)first_layer_addr != original_value) {
131 T_FAIL("first_layer_addr should not have changed");
132 fail++;
133 }
134 if (*(int *)shared_addr != 0x1234) {
135 T_FAIL("shared_addr should have changed");
136 fail++;
137 }
138 if (*(int*)cow_addr != original_value) {
139 T_FAIL("cow_addr should not have changed");
140 fail++;
141 }
142 // T_LOG("pause...");
143 // getchar();
144 }
145
146 T_DECL(vm_test_90774260, "Test MAP_MEM_VM_COPY security", T_META_TAG_VM_PREFERRED)
147 {
148 test_90774260();
149 }
150