This is xnu-11215.1.10. See this file in:
#include <darwintest.h>
#include <stdlib.h>
#include <mach/mach_host.h>
#include <mach/mach_init.h>
#include <mach/mach_vm.h>
#include <mach/vm_map.h>
T_GLOBAL_META(
T_META_NAMESPACE("xnu.vm"),
T_META_RADAR_COMPONENT_NAME("xnu"),
T_META_RADAR_COMPONENT_VERSION("VM"));
void
test_90774260(void)
{
kern_return_t kr;
mach_vm_size_t vm_size = 1024 * 1024;
int fail = 0;
int original_value;
uint64_t first_layer_addr = 0;
mach_port_t first_layer_entry_port = 0;
kr = mach_memory_object_memory_entry(mach_host_self(),
1, (vm_size_t) vm_size,
VM_PROT_READ | VM_PROT_WRITE,
0, &first_layer_entry_port);
if (kr == MIG_BAD_ID) {
T_FAIL("mach_memory_object_memory_entry() returned MIG_BAD_ID");
return;
}
#if __arm64__ && !__LP64__
/*
* mach_memory_object_memory_entry() is broken on arm64_32.
* Use mach_make_memory_entry_64(MAP_MEM_NAMED_CREATE) instead.
*/
if (kr == MIG_BAD_ARGUMENTS) {
T_LOG("mach_memory_object_memory_entry() returned MIG_BAD_ARGUMENTS (because broken on arm64_32)");
memory_object_size_t me_size = vm_size;
kr = mach_make_memory_entry_64(mach_task_self(),
&me_size,
0,
VM_PROT_READ | VM_PROT_WRITE | MAP_MEM_NAMED_CREATE,
&first_layer_entry_port,
MACH_PORT_NULL);
T_ASSERT_MACH_SUCCESS(kr, "mach_make_memory_entry_64(MAP_MEM_NAMED_CREATE)");
} else
#endif /* __arm64__ && !__LP64__ */
{
T_ASSERT_MACH_SUCCESS(kr, "mach_memory_object_memory_entry()");
}
// map the memory to our space
kr = mach_vm_map(mach_task_self(),
&first_layer_addr,
vm_size,
0, /* mask */
VM_FLAGS_ANYWHERE,
first_layer_entry_port,
0, /* offset */
0, /* copy */
VM_PROT_READ | VM_PROT_WRITE,
VM_PROT_READ | VM_PROT_WRITE,
VM_INHERIT_DEFAULT);
T_ASSERT_MACH_SUCCESS(kr, "mach_vm_map(first_layer_addr)");
original_value = 0xabcd;
*(int*)first_layer_addr = original_value;
// create a COW port
mach_port_t cow_port = MACH_PORT_NULL;
mach_vm_size_t me_size = vm_size;
kr = mach_make_memory_entry_64(mach_task_self(),
&me_size,
first_layer_addr,
(VM_PROT_READ | VM_PROT_WRITE | MAP_MEM_VM_COPY),
&cow_port,
0);
T_ASSERT_MACH_SUCCESS(kr, "mach_make_memory_entry_64()");
T_QUIET; T_ASSERT_EQ(me_size, vm_size, "incomplete memory entry");
// map cow port to a new address in the shared way
uint64_t shared_addr = 0;
kr = mach_vm_map(mach_task_self(),
&shared_addr,
vm_size,
0, /* mask */
VM_FLAGS_ANYWHERE,
cow_port,
0, /* offset */
0, /* copy */
VM_PROT_READ | VM_PROT_WRITE,
VM_PROT_READ | VM_PROT_WRITE,
VM_INHERIT_DEFAULT);
T_ASSERT_MACH_SUCCESS(kr, "mach_vm_map(shared_addr)");
// map cow port to a new address in the COW way
uint64_t cow_addr = 0;
kr = mach_vm_map(mach_task_self(),
&cow_addr,
vm_size,
0, /* mask */
VM_FLAGS_ANYWHERE,
cow_port,
0, /* offset */
1, /* copy */
VM_PROT_READ | VM_PROT_WRITE,
VM_PROT_READ | VM_PROT_WRITE,
VM_INHERIT_DEFAULT);
T_ASSERT_MACH_SUCCESS(kr, "mach_vm_map(cow_addr)");
// T_LOG("first_layer_addr = 0x%llx", first_layer_addr);
// T_LOG("shared_addr = 0x%llx\n", shared_addr);
// T_LOG("cow_addr = 0x%llx\n", cow_addr);
// T_LOG("*(int*)first_layer_addr = 0x%x", *(int*)first_layer_addr);
// T_LOG("*(int*)shared_addr = 0x%x\n", *(int*)shared_addr);
// T_LOG("*(int*)shared_addr2 = 0x%x\n", *(int*)shared_addr2);
// T_LOG("*(int*)cow_addr = 0x%x\n", *(int*)cow_addr);
T_LOG("write 0x%x to *(int*)shared_addr", 0x1234);
*(int*)shared_addr = 0x1234;
T_LOG("*(int*)first_layer_addr = 0x%x", *(int*)first_layer_addr);
T_LOG("*(int*)shared_addr = 0x%x\n", *(int*)shared_addr);
T_LOG("*(int*)cow_addr = 0x%x\n", *(int*)cow_addr);
if (*(int*)first_layer_addr != original_value) {
T_FAIL("first_layer_addr should not have changed");
fail++;
}
if (*(int *)shared_addr != 0x1234) {
T_FAIL("shared_addr should have changed");
fail++;
}
if (*(int*)cow_addr != original_value) {
T_FAIL("cow_addr should not have changed");
fail++;
}
// T_LOG("pause...");
// getchar();
}
T_DECL(vm_test_90774260, "Test MAP_MEM_VM_COPY security", T_META_TAG_VM_PREFERRED)
{
test_90774260();
}