Files
sdk/runtime/vm/virtual_memory.cc
T
Vyacheslav Egorov 6c92ce6049 [vm] Make sure to use MAP_JIT for callback pages
This is follow up to bd57548 which switched us to use manual copying
for call back pages on Mac OS and iOS. However these newly allocated
pages need to be created with MAP_JIT flag otherwise OS will kill
us with code signing violation if hardened runtime is enabled.

This can only be observed when the binary is signed that's why
we have not seen it on CI.

TEST=manually signed and tested that it no longer crashes.

Fixes https://github.com/dart-lang/sdk/issues/53928

Change-Id: Ic15673d354d4fdf1bb8179066b37c7ae90877982
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/333260
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
Commit-Queue: Slava Egorov <vegorov@google.com>
2023-11-01 22:38:27 +00:00

97 lines
3.6 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)
// 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