diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-09-07 13:12:05 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-11-09 10:02:59 +0000 |
commit | 33fc33aa94d4add0878ec30dc818e34e1dd3cc2a (patch) | |
tree | f6af110909c79b2759136554f1143d8b0572af0a /chromium/gin | |
parent | 7d2c5d177e9813077a621df8d18c0deda73099b3 (diff) | |
download | qtwebengine-chromium-33fc33aa94d4add0878ec30dc818e34e1dd3cc2a.tar.gz |
BASELINE: Update Chromium to 104.0.5112.120
Change-Id: I5d2726c2ab018d75d055739b6ba64317904f05bb
Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/438935
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/gin')
-rw-r--r-- | chromium/gin/array_buffer.cc | 137 | ||||
-rw-r--r-- | chromium/gin/array_buffer.h | 21 | ||||
-rw-r--r-- | chromium/gin/per_context_data.cc | 4 | ||||
-rw-r--r-- | chromium/gin/v8_initializer.cc | 35 | ||||
-rw-r--r-- | chromium/gin/v8_isolate_memory_dump_provider_unittest.cc | 9 | ||||
-rw-r--r-- | chromium/gin/v8_platform.cc | 9 | ||||
-rw-r--r-- | chromium/gin/v8_platform_page_allocator.cc | 14 | ||||
-rw-r--r-- | chromium/gin/v8_platform_page_allocator.h | 4 | ||||
-rw-r--r-- | chromium/gin/v8_platform_page_allocator_unittest.cc | 12 |
9 files changed, 217 insertions, 28 deletions
diff --git a/chromium/gin/array_buffer.cc b/chromium/gin/array_buffer.cc index 2e78aa60fc9..0adc026db8e 100644 --- a/chromium/gin/array_buffer.cc +++ b/chromium/gin/array_buffer.cc @@ -8,9 +8,13 @@ #include <stdlib.h> #include "base/allocator/partition_allocator/page_allocator.h" +#include "base/allocator/partition_allocator/partition_alloc.h" +#include "base/bits.h" #include "base/check_op.h" +#include "base/no_destructor.h" #include "build/build_config.h" #include "gin/per_isolate_data.h" +#include "v8/include/v8-initialization.h" #if BUILDFLAG(IS_POSIX) #include <sys/mman.h> @@ -26,25 +30,64 @@ static_assert(V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT == 2, "array buffers must have two internal fields"); // ArrayBufferAllocator ------------------------------------------------------- +base::ThreadSafePartitionRoot* ArrayBufferAllocator::partition_ = nullptr; void* ArrayBufferAllocator::Allocate(size_t length) { - // TODO(bbudge) Use partition allocator for malloc/calloc allocations. - return calloc(1, length); + unsigned int flags = partition_alloc::AllocFlags::kZeroFill | + partition_alloc::AllocFlags::kReturnNull; + return AllocateInternal(length, flags); } void* ArrayBufferAllocator::AllocateUninitialized(size_t length) { - return malloc(length); + unsigned int flags = partition_alloc::AllocFlags::kReturnNull; + return AllocateInternal(length, flags); +} + +void* ArrayBufferAllocator::AllocateInternal(size_t length, + unsigned int flags) { +#ifdef V8_ENABLE_SANDBOX + // The V8 sandbox requires all ArrayBuffer backing stores to be allocated + // inside the sandbox address space. This isn't guaranteed if allocation + // override hooks (which are e.g. used by GWP-ASan) are enabled or if a + // memory tool (e.g. ASan) overrides malloc, so disable both. + flags |= partition_alloc::AllocFlags::kNoOverrideHooks; + flags |= partition_alloc::AllocFlags::kNoMemoryToolOverride; +#endif + return partition_->AllocWithFlags(flags, length, "gin::ArrayBufferAllocator"); } void ArrayBufferAllocator::Free(void* data, size_t length) { - free(data); + unsigned int flags = 0; +#ifdef V8_ENABLE_SANDBOX + // See |AllocateInternal|. + flags |= partition_alloc::FreeFlags::kNoMemoryToolOverride; +#endif + partition_->FreeWithFlags(flags, data); } +// static ArrayBufferAllocator* ArrayBufferAllocator::SharedInstance() { static ArrayBufferAllocator* instance = new ArrayBufferAllocator(); return instance; } +// static +void ArrayBufferAllocator::InitializePartition() { + static base::NoDestructor<base::PartitionAllocator> partition_allocator{}; + + // These configuration options are copied from blink's ArrayBufferPartition. + partition_allocator->init({ + base::PartitionOptions::AlignedAlloc::kDisallowed, + base::PartitionOptions::ThreadCache::kDisabled, + base::PartitionOptions::Quarantine::kAllowed, + base::PartitionOptions::Cookie::kAllowed, + base::PartitionOptions::BackupRefPtr::kDisabled, + base::PartitionOptions::UseConfigurablePool::kIfAvailable, + }); + + partition_ = partition_allocator->root(); +} + // ArrayBuffer ---------------------------------------------------------------- ArrayBuffer::ArrayBuffer() = default; @@ -96,4 +139,90 @@ bool Converter<ArrayBufferView>::FromV8(v8::Isolate* isolate, return true; } +// ArrayBufferSharedMemoryMapper --------------------------------------------- + +namespace { +#ifdef V8_ENABLE_SANDBOX +// When the V8 sandbox is enabled, shared memory backing ArrayBuffers must be +// mapped into the sandbox address space. This custom SharedMemoryMapper +// implements this. + +class ArrayBufferSharedMemoryMapper : public base::SharedMemoryMapper { + public: + absl::optional<base::span<uint8_t>> Map( + base::subtle::PlatformSharedMemoryHandle handle, + bool write_allowed, + uint64_t offset, + size_t size) override { + v8::VirtualAddressSpace* address_space = v8::V8::GetSandboxAddressSpace(); + size_t allocation_granularity = address_space->allocation_granularity(); + + v8::PlatformSharedMemoryHandle v8_handle; +#if BUILDFLAG(IS_MAC) + v8_handle = v8::SharedMemoryHandleFromMachMemoryEntry(handle); +#elif BUILDFLAG(IS_FUCHSIA) + v8_handle = v8::SharedMemoryHandleFromVMO(handle->get()); +#elif BUILDFLAG(IS_WIN) + v8_handle = v8::SharedMemoryHandleFromFileMapping(handle); +#elif BUILDFLAG(IS_ANDROID) + v8_handle = v8::SharedMemoryHandleFromFileDescriptor(handle); +#elif BUILDFLAG(IS_POSIX) + v8_handle = v8::SharedMemoryHandleFromFileDescriptor(handle.fd); +#else +#error "Unknown platform" +#endif + + // Size and offset must be a multiple of the page allocation granularity. + // The caller already ensures that the offset is a multiple of the + // allocation granularity though. + CHECK_EQ(0UL, offset % allocation_granularity); + size_t mapping_size = base::bits::AlignUp(size, allocation_granularity); + + v8::PagePermissions permissions = write_allowed + ? v8::PagePermissions::kReadWrite + : v8::PagePermissions::kRead; + uintptr_t mapping = v8::V8::GetSandboxAddressSpace()->AllocateSharedPages( + 0, mapping_size, permissions, v8_handle, offset); + if (!mapping) + return absl::nullopt; + + return base::make_span(reinterpret_cast<uint8_t*>(mapping), size); + } + + void Unmap(base::span<uint8_t> mapping) override { + v8::VirtualAddressSpace* address_space = v8::V8::GetSandboxAddressSpace(); + size_t allocation_granularity = address_space->allocation_granularity(); + + uintptr_t address = reinterpret_cast<uintptr_t>(mapping.data()); + CHECK_EQ(0UL, address % allocation_granularity); + size_t mapping_size = + base::bits::AlignUp(mapping.size(), allocation_granularity); + + address_space->FreeSharedPages(address, mapping_size); + } +}; +#endif // V8_ENABLE_SANDBOX + +base::SharedMemoryMapper* CreateSharedMemoryMapperForArrayBuffers() { +#if V8_ENABLE_SANDBOX + static ArrayBufferSharedMemoryMapper instance; + // Currently, it is still possible for the sandbox to be disabled at runtime + // (by not initializing it), in which case the default shared memory mapper + // must be used. In the future, this will no longer be allowed and this helper + // function can then be removed entirely. + // TODO(saelo) remove once sandbox initialization is mandatory. + if (v8::V8::GetSandboxSizeInBytes() > 0) + return &instance; + else +#endif + return base::SharedMemoryMapper::GetDefaultInstance(); +} +} // namespace + +base::SharedMemoryMapper* GetSharedMemoryMapperForArrayBuffers() { + static base::SharedMemoryMapper* mapper = + CreateSharedMemoryMapperForArrayBuffers(); + return mapper; +} + } // namespace gin diff --git a/chromium/gin/array_buffer.h b/chromium/gin/array_buffer.h index 8dfcf65b5b5..ad51ab9cd7f 100644 --- a/chromium/gin/array_buffer.h +++ b/chromium/gin/array_buffer.h @@ -8,8 +8,10 @@ #include <stddef.h> #include <stdint.h> +#include "base/allocator/partition_allocator/partition_alloc.h" #include "base/compiler_specific.h" #include "base/memory/ref_counted.h" +#include "base/memory/shared_memory_mapper.h" #include "gin/converter.h" #include "gin/gin_export.h" #include "v8/include/v8-array-buffer.h" @@ -24,6 +26,23 @@ class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { void Free(void* data, size_t length) override; GIN_EXPORT static ArrayBufferAllocator* SharedInstance(); + + private: + friend class V8Initializer; + + void* AllocateInternal(size_t length, unsigned int flags); + + // Initialize the PartitionAlloc partition from which instances of this class + // allocate memory. This is called after initializing V8 since, when enabled, + // the V8 sandbox must be initialized first. + static void InitializePartition(); + + // The PartitionAlloc partition that instances of this class allocate memory + // chunks from. When the V8 sandbox is enabled, this partition must be placed + // inside of it. For that, PA's ConfigurablePool is created inside the V8 + // sandbox during initialization of V8, and this partition is then placed + // inside the configurable pool during InitializePartition(). + static base::ThreadSafePartitionRoot* partition_; }; class GIN_EXPORT ArrayBuffer { @@ -76,6 +95,8 @@ struct GIN_EXPORT Converter<ArrayBufferView> { ArrayBufferView* out); }; +GIN_EXPORT base::SharedMemoryMapper* GetSharedMemoryMapperForArrayBuffers(); + } // namespace gin #endif // GIN_ARRAY_BUFFER_H_ diff --git a/chromium/gin/per_context_data.cc b/chromium/gin/per_context_data.cc index 6c6eda507e4..f55aaa15ff7 100644 --- a/chromium/gin/per_context_data.cc +++ b/chromium/gin/per_context_data.cc @@ -13,13 +13,13 @@ PerContextData::PerContextData(ContextHolder* context_holder, v8::Local<v8::Context> context) : context_holder_(context_holder), runner_(nullptr) { context->SetAlignedPointerInEmbedderData( - kPerContextDataStartIndex + kEmbedderNativeGin, this); + int{kPerContextDataStartIndex} + kEmbedderNativeGin, this); } PerContextData::~PerContextData() { v8::HandleScope handle_scope(context_holder_->isolate()); context_holder_->context()->SetAlignedPointerInEmbedderData( - kPerContextDataStartIndex + kEmbedderNativeGin, NULL); + int{kPerContextDataStartIndex} + kEmbedderNativeGin, NULL); } // static diff --git a/chromium/gin/v8_initializer.cc b/chromium/gin/v8_initializer.cc index 9dddcdf88d5..b908194f581 100644 --- a/chromium/gin/v8_initializer.cc +++ b/chromium/gin/v8_initializer.cc @@ -34,6 +34,7 @@ #include "base/threading/platform_thread.h" #include "base/time/time.h" #include "build/build_config.h" +#include "gin/array_buffer.h" #include "gin/gin_features.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "v8/include/v8-initialization.h" @@ -372,11 +373,11 @@ void V8Initializer::Initialize(IsolateHolder::ScriptMode mode, // of the virtual memory cage, already use V8's random number generator. v8::V8::SetEntropySource(&GenerateEntropy); -#if defined(V8_SANDBOX) +#if defined(V8_ENABLE_SANDBOX) static_assert(ARCH_CPU_64_BITS, "V8 sandbox can only work in 64-bit builds"); // For now, initializing the sandbox is optional, and we only do it if the // correpsonding feature is enabled. In the future, it will be mandatory when - // compiling with V8_SANDBOX. + // compiling with V8_ENABLE_SANDBOX. // However, if V8 uses sandboxed pointers, then the sandbox must be // initialized as sandboxed pointers are simply offsets inside the sandbox. #if defined(V8_SANDBOXED_POINTERS) @@ -405,7 +406,7 @@ void V8Initializer::Initialize(IsolateHolder::ScriptMode mode, // TODO(1218005) remove this once the finch trial has ended. base::UmaHistogramSparse("V8.VirtualMemoryCageSizeGB", sizeInGB); } -#endif // V8_SANDBOX +#endif // V8_ENABLE_SANDBOX #if defined(V8_USE_EXTERNAL_STARTUP_DATA) if (g_mapped_snapshot) { @@ -419,7 +420,7 @@ void V8Initializer::Initialize(IsolateHolder::ScriptMode mode, v8_is_initialized = true; -#if defined(V8_SANDBOX) +#if defined(V8_ENABLE_SANDBOX) if (v8_sandbox_is_initialized) { // These values are persisted to logs. Entries should not be renumbered and // numeric values should never be reused. This should match enum @@ -441,10 +442,10 @@ void V8Initializer::Initialize(IsolateHolder::ScriptMode mode, // and Blink then creates the ArrayBuffer partition in that Pool. v8::VirtualAddressSpace* sandbox_address_space = v8::V8::GetSandboxAddressSpace(); - const size_t max_pool_size = - base::internal::PartitionAddressSpace::ConfigurablePoolMaxSize(); - const size_t min_pool_size = - base::internal::PartitionAddressSpace::ConfigurablePoolMinSize(); + const size_t max_pool_size = partition_alloc::internal:: + PartitionAddressSpace::ConfigurablePoolMaxSize(); + const size_t min_pool_size = partition_alloc::internal:: + PartitionAddressSpace::ConfigurablePoolMinSize(); size_t pool_size = max_pool_size; #if BUILDFLAG(IS_WIN) // On Windows prior to 8.1 we allocate a smaller Pool since reserving @@ -474,11 +475,23 @@ void V8Initializer::Initialize(IsolateHolder::ScriptMode mode, } // The V8 sandbox is guaranteed to be large enough to host the pool. CHECK(pool_base); - base::internal::PartitionAddressSpace::InitConfigurablePool(pool_base, - pool_size); + partition_alloc::internal::PartitionAddressSpace::InitConfigurablePool( + pool_base, pool_size); // TODO(saelo) maybe record the size of the Pool into UMA. + + // If this CHECK fails, it means that something used the array buffer + // shared memory mapper before the sandbox was initialized, which may then + // cause crashes later on as array buffers may have been mapped outside the + // sandbox. See GetSharedMemoryMapperForArrayBuffers(). TODO(saelo) remove + // once sandbox initialization is mandatory. + CHECK_NE(nullptr, GetSharedMemoryMapperForArrayBuffers()); } -#endif // V8_SANDBOX +#endif // V8_ENABLE_SANDBOX + + // Initialize the partition used by gin::ArrayBufferAllocator instances. This + // needs to happen now, after the V8 sandbox has been initialized, so that + // the partition is placed inside the configurable pool initialized above. + ArrayBufferAllocator::InitializePartition(); } // static diff --git a/chromium/gin/v8_isolate_memory_dump_provider_unittest.cc b/chromium/gin/v8_isolate_memory_dump_provider_unittest.cc index cbc02c2a33b..768156d85a6 100644 --- a/chromium/gin/v8_isolate_memory_dump_provider_unittest.cc +++ b/chromium/gin/v8_isolate_memory_dump_provider_unittest.cc @@ -10,6 +10,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/process_memory_dump.h" #include "base/trace_event/trace_event.h" +#include "build/build_config.h" #include "gin/public/isolate_holder.h" #include "gin/test/v8_test.h" #include "v8/include/v8-initialization.h" @@ -187,7 +188,13 @@ TEST_F(V8MemoryDumpProviderTest, DumpCodeStatistics) { } // Tests that a deterministic memory dump request performs a GC. -TEST_F(V8MemoryDumpProviderTest, Deterministic) { +// TODO(crbug.com/1318974): Fix the flakiness on Linux. +#if BUILDFLAG(IS_LINUX) +#define MAYBE_Deterministic DISABLED_Deterministic +#else +#define MAYBE_Deterministic Deterministic +#endif +TEST_F(V8MemoryDumpProviderTest, MAYBE_Deterministic) { base::trace_event::MemoryDumpArgs dump_args = { base::trace_event::MemoryDumpLevelOfDetail::LIGHT, base::trace_event::MemoryDumpDeterminism::FORCE_GC}; diff --git a/chromium/gin/v8_platform.cc b/chromium/gin/v8_platform.cc index 952023235d9..03cbb536f9a 100644 --- a/chromium/gin/v8_platform.cc +++ b/chromium/gin/v8_platform.cc @@ -157,7 +157,8 @@ class TimeClamper { private: inline double ThresholdFor(double clamped_time) const { - uint64_t time_hash = MurmurHash3(bit_cast<int64_t>(clamped_time) ^ secret_); + uint64_t time_hash = + MurmurHash3(base::bit_cast<int64_t>(clamped_time) ^ secret_); return clamped_time + kResolutionSeconds * ToDouble(time_hash); } @@ -166,7 +167,7 @@ class TimeClamper { static const uint64_t kExponentBits = uint64_t{0x3FF0000000000000}; static const uint64_t kMantissaMask = uint64_t{0x000FFFFFFFFFFFFF}; uint64_t random = (value & kMantissaMask) | kExponentBits; - return bit_cast<double>(random) - 1; + return base::bit_cast<double>(random) - 1; } static inline uint64_t MurmurHash3(uint64_t value) { @@ -394,7 +395,7 @@ std::shared_ptr<v8::TaskRunner> V8Platform::GetForegroundTaskRunner( int V8Platform::NumberOfWorkerThreads() { // V8Platform assumes the scheduler uses the same set of workers for default // and user blocking tasks. - const int num_foreground_workers = + const size_t num_foreground_workers = base::ThreadPoolInstance::Get() ->GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated( kDefaultTaskTraits); @@ -402,7 +403,7 @@ int V8Platform::NumberOfWorkerThreads() { base::ThreadPoolInstance::Get() ->GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated( kBlockingTaskTraits)); - return std::max(1, num_foreground_workers); + return std::max(1, static_cast<int>(num_foreground_workers)); } void V8Platform::CallOnWorkerThread(std::unique_ptr<v8::Task> task) { diff --git a/chromium/gin/v8_platform_page_allocator.cc b/chromium/gin/v8_platform_page_allocator.cc index b1be62dbed0..2345b2d71b5 100644 --- a/chromium/gin/v8_platform_page_allocator.cc +++ b/chromium/gin/v8_platform_page_allocator.cc @@ -9,6 +9,7 @@ #include "base/allocator/partition_allocator/random.h" #include "base/check_op.h" #include "base/cpu.h" +#include "base/memory/page_size.h" #include "build/build_config.h" namespace { @@ -54,11 +55,11 @@ namespace gin { PageAllocator::~PageAllocator() = default; size_t PageAllocator::AllocatePageSize() { - return base::PageAllocationGranularity(); + return partition_alloc::internal::PageAllocationGranularity(); } size_t PageAllocator::CommitPageSize() { - return base::SystemPageSize(); + return base::GetPageSize(); } void PageAllocator::SetRandomMmapSeed(int64_t seed) { @@ -124,6 +125,15 @@ bool PageAllocator::SetPermissions(void* address, } } +bool PageAllocator::RecommitPages(void* address, + size_t length, + Permission permissions) { + base::RecommitSystemPages( + reinterpret_cast<uintptr_t>(address), length, GetPageConfig(permissions), + base::PageAccessibilityDisposition::kAllowKeepForPerf); + return true; +} + bool PageAllocator::DiscardSystemPages(void* address, size_t size) { base::DiscardSystemPages(address, size); return true; diff --git a/chromium/gin/v8_platform_page_allocator.h b/chromium/gin/v8_platform_page_allocator.h index bf573d46702..68e68c2e4fb 100644 --- a/chromium/gin/v8_platform_page_allocator.h +++ b/chromium/gin/v8_platform_page_allocator.h @@ -44,6 +44,10 @@ class GIN_EXPORT PageAllocator final : public v8::PageAllocator { size_t length, Permission permissions) override; + bool RecommitPages(void* address, + size_t length, + Permission permissions) override; + bool DiscardSystemPages(void* address, size_t size) override; bool DecommitPages(void* address, size_t size) override; diff --git a/chromium/gin/v8_platform_page_allocator_unittest.cc b/chromium/gin/v8_platform_page_allocator_unittest.cc index efc620951c7..fe13330d721 100644 --- a/chromium/gin/v8_platform_page_allocator_unittest.cc +++ b/chromium/gin/v8_platform_page_allocator_unittest.cc @@ -57,8 +57,10 @@ using BTITestFunction = int64_t (*)(int64_t); TEST(V8PlatformPageAllocatorBTITest, VerifyReadExecutePagesAreProtected) { auto page_allocator = gin::PageAllocator(); - auto const memory_size = base::PageAllocationGranularity(); - auto const memory_alignment = base::PageAllocationGranularity(); + auto const memory_size = + partition_alloc::internal::PageAllocationGranularity(); + auto const memory_alignment = + partition_alloc::internal::PageAllocationGranularity(); // Next, map some read-write memory and copy some test helper functions there. char* const buffer = reinterpret_cast<char*>(page_allocator.AllocatePages( @@ -114,8 +116,10 @@ TEST(V8PlatformPageAllocatorBTITest, VerifyReadExecutePagesAreProtected) { TEST(V8PlatformAllocatorBTITest, VerifyReadWriteExecutePagesAreNotProtected) { auto page_allocator = gin::PageAllocator(); - auto const memory_size = base::PageAllocationGranularity(); - auto const memory_alignment = base::PageAllocationGranularity(); + auto const memory_size = + partition_alloc::internal::PageAllocationGranularity(); + auto const memory_alignment = + partition_alloc::internal::PageAllocationGranularity(); // Next, map some read-write memory and copy some test helper functions there. char* const buffer = reinterpret_cast<char*>(page_allocator.AllocatePages( |