Files
sdk/runtime/vm/virtual_memory.cc
T
Daco Harkes bd57548de1 [vm/ffi] Fix FFI callbacks on iOS 17
The new Secure Page Table Monitor in iOS on A15 and A16 does not allow
`vm_remap`ping memory pages that are manually created. It only allows
remapping pages which come directly from a signed binary.

Manually copying the pages is supported in JIT mode.

TEST=manually tested locally in a local-engine build

Bug: https://github.com/flutter/flutter/issues/136980
Change-Id: I94d87f753a50648486f46fe728dd8358038971fe
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/332241
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Daco Harkes <dacoharkes@google.com>
2023-10-25 14:00:02 +00:00

98 lines
3.7 KiB
C++

// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/virtual_memory.h"
#include "platform/assert.h"
#include "platform/utils.h"
#if defined(DART_HOST_OS_MACOS)
#include <mach/mach.h>
#endif
namespace dart {
bool VirtualMemory::InSamePage(uword address0, uword address1) {
return (Utils::RoundDown(address0, PageSize()) ==
Utils::RoundDown(address1, PageSize()));
}
void VirtualMemory::Truncate(intptr_t new_size) {
ASSERT(Utils::IsAligned(new_size, PageSize()));
ASSERT(new_size <= size());
if (reserved_.size() ==
region_.size()) { // Don't create holes in reservation.
if (FreeSubSegment(reinterpret_cast<void*>(start() + new_size),
size() - new_size)) {
reserved_.set_size(new_size);
if (AliasOffset() != 0) {
FreeSubSegment(reinterpret_cast<void*>(alias_.start() + new_size),
alias_.size() - new_size);
}
}
}
region_.Subregion(region_, 0, new_size);
alias_.Subregion(alias_, 0, new_size);
}
VirtualMemory* VirtualMemory::ForImagePage(void* pointer, uword size) {
// Memory for precompilated instructions was allocated by the embedder, so
// create a VirtualMemory without allocating.
MemoryRegion region(pointer, size);
MemoryRegion reserved(nullptr, 0); // null reservation indicates VM should
// not attempt to free this memory.
VirtualMemory* memory = new VirtualMemory(region, region, reserved);
ASSERT(!memory->vm_owns_region());
return memory;
}
#if !defined(DART_TARGET_OS_FUCHSIA)
// TODO(52579): Reenable on Fuchsia.
bool VirtualMemory::DuplicateRX(VirtualMemory* target) {
const intptr_t aligned_size = Utils::RoundUp(size(), PageSize());
ASSERT_LESS_OR_EQUAL(aligned_size, target->size());
#if defined(DART_HOST_OS_MACOS) && \
(defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER))
// Mac is special cased because iOS doesn't allow allocating new executable
// memory, so the default approach would fail. We are allowed to make new
// mappings of existing executable memory using vm_remap though, which is
// effectively the same for non-writable memory.
const mach_port_t task = mach_task_self();
const vm_address_t source_address = reinterpret_cast<vm_address_t>(address());
const vm_size_t mem_size = aligned_size;
const vm_prot_t read_execute = VM_PROT_READ | VM_PROT_EXECUTE;
vm_prot_t current_protection = read_execute;
vm_prot_t max_protection = read_execute;
vm_address_t target_address =
reinterpret_cast<vm_address_t>(target->address());
kern_return_t status = vm_remap(
task, &target_address, mem_size,
/*mask=*/0,
/*flags=*/VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE, task, source_address,
/*copy=*/true, &current_protection, &max_protection,
/*inheritance=*/VM_INHERIT_NONE);
if (status != KERN_SUCCESS) {
return false;
}
ASSERT(reinterpret_cast<void*>(target_address) == target->address());
ASSERT_EQUAL(current_protection & read_execute, read_execute);
ASSERT_EQUAL(max_protection & read_execute, read_execute);
return true;
#else // defined(DART_HOST_OS_MACOS)
// TODO(52497): Use dual mapping on platforms where it's supported.
// Check that target doesn't overlap with this.
ASSERT(target->start() >= end() || target->end() <= start());
memcpy(target->address(), address(), size()); // NOLINT
Protect(target->address(), aligned_size, kReadExecute);
return true;
#endif // defined(DART_HOST_OS_MACOS)
}
#endif // !defined(DART_TARGET_OS_FUCHSIA)
} // namespace dart