array_buffer.cc 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. // Copyright 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "gin/array_buffer.h"
  5. #include <stddef.h>
  6. #include <stdlib.h>
  7. #include "base/allocator/partition_allocator/page_allocator.h"
  8. #include "base/allocator/partition_allocator/partition_alloc.h"
  9. #include "base/bits.h"
  10. #include "base/check_op.h"
  11. #include "base/no_destructor.h"
  12. #include "build/build_config.h"
  13. #include "gin/per_isolate_data.h"
  14. #include "v8/include/v8-initialization.h"
  15. #if BUILDFLAG(IS_POSIX)
  16. #include <sys/mman.h>
  17. #ifndef MAP_ANONYMOUS
  18. #define MAP_ANONYMOUS MAP_ANON
  19. #endif
  20. #endif // BUILDFLAG(IS_POSIX)
  21. namespace gin {
  22. static_assert(V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT == 2,
  23. "array buffers must have two internal fields");
  24. // ArrayBufferAllocator -------------------------------------------------------
  25. partition_alloc::ThreadSafePartitionRoot* ArrayBufferAllocator::partition_ =
  26. nullptr;
  27. void* ArrayBufferAllocator::Allocate(size_t length) {
  28. unsigned int flags = partition_alloc::AllocFlags::kZeroFill |
  29. partition_alloc::AllocFlags::kReturnNull;
  30. return AllocateInternal(length, flags);
  31. }
  32. void* ArrayBufferAllocator::AllocateUninitialized(size_t length) {
  33. unsigned int flags = partition_alloc::AllocFlags::kReturnNull;
  34. return AllocateInternal(length, flags);
  35. }
  36. void* ArrayBufferAllocator::AllocateInternal(size_t length,
  37. unsigned int flags) {
  38. #ifdef V8_ENABLE_SANDBOX
  39. // The V8 sandbox requires all ArrayBuffer backing stores to be allocated
  40. // inside the sandbox address space. This isn't guaranteed if allocation
  41. // override hooks (which are e.g. used by GWP-ASan) are enabled or if a
  42. // memory tool (e.g. ASan) overrides malloc, so disable both.
  43. flags |= partition_alloc::AllocFlags::kNoOverrideHooks;
  44. flags |= partition_alloc::AllocFlags::kNoMemoryToolOverride;
  45. #endif
  46. return partition_->AllocWithFlags(flags, length, "gin::ArrayBufferAllocator");
  47. }
  48. void ArrayBufferAllocator::Free(void* data, size_t length) {
  49. unsigned int flags = 0;
  50. #ifdef V8_ENABLE_SANDBOX
  51. // See |AllocateInternal|.
  52. flags |= partition_alloc::FreeFlags::kNoMemoryToolOverride;
  53. #endif
  54. partition_->FreeWithFlags(flags, data);
  55. }
  56. // static
  57. ArrayBufferAllocator* ArrayBufferAllocator::SharedInstance() {
  58. static ArrayBufferAllocator* instance = new ArrayBufferAllocator();
  59. return instance;
  60. }
  61. // static
  62. void ArrayBufferAllocator::InitializePartition() {
  63. static base::NoDestructor<partition_alloc::PartitionAllocator>
  64. partition_allocator{};
  65. // These configuration options are copied from blink's ArrayBufferPartition.
  66. partition_allocator->init({
  67. partition_alloc::PartitionOptions::AlignedAlloc::kDisallowed,
  68. partition_alloc::PartitionOptions::ThreadCache::kDisabled,
  69. partition_alloc::PartitionOptions::Quarantine::kAllowed,
  70. partition_alloc::PartitionOptions::Cookie::kAllowed,
  71. partition_alloc::PartitionOptions::BackupRefPtr::kDisabled,
  72. partition_alloc::PartitionOptions::BackupRefPtrZapping::kDisabled,
  73. partition_alloc::PartitionOptions::UseConfigurablePool::kIfAvailable,
  74. });
  75. partition_ = partition_allocator->root();
  76. }
  77. // ArrayBuffer ----------------------------------------------------------------
  78. ArrayBuffer::ArrayBuffer() = default;
  79. ArrayBuffer::ArrayBuffer(v8::Isolate* isolate, v8::Local<v8::ArrayBuffer> array)
  80. : backing_store_(array->GetBackingStore()) {}
  81. ArrayBuffer::~ArrayBuffer() = default;
  82. ArrayBuffer& ArrayBuffer::operator=(const ArrayBuffer& other) = default;
  83. // Converter<ArrayBuffer> -----------------------------------------------------
  84. bool Converter<ArrayBuffer>::FromV8(v8::Isolate* isolate,
  85. v8::Local<v8::Value> val,
  86. ArrayBuffer* out) {
  87. if (!val->IsArrayBuffer())
  88. return false;
  89. *out = ArrayBuffer(isolate, v8::Local<v8::ArrayBuffer>::Cast(val));
  90. return true;
  91. }
  92. // ArrayBufferView ------------------------------------------------------------
  93. ArrayBufferView::ArrayBufferView()
  94. : offset_(0),
  95. num_bytes_(0) {
  96. }
  97. ArrayBufferView::ArrayBufferView(v8::Isolate* isolate,
  98. v8::Local<v8::ArrayBufferView> view)
  99. : array_buffer_(isolate, view->Buffer()),
  100. offset_(view->ByteOffset()),
  101. num_bytes_(view->ByteLength()) {
  102. }
  103. ArrayBufferView::~ArrayBufferView() = default;
  104. ArrayBufferView& ArrayBufferView::operator=(const ArrayBufferView& other) =
  105. default;
  106. // Converter<ArrayBufferView> -------------------------------------------------
  107. bool Converter<ArrayBufferView>::FromV8(v8::Isolate* isolate,
  108. v8::Local<v8::Value> val,
  109. ArrayBufferView* out) {
  110. if (!val->IsArrayBufferView())
  111. return false;
  112. *out = ArrayBufferView(isolate, v8::Local<v8::ArrayBufferView>::Cast(val));
  113. return true;
  114. }
  115. // ArrayBufferSharedMemoryMapper ---------------------------------------------
  116. namespace {
  117. #ifdef V8_ENABLE_SANDBOX
  118. // When the V8 sandbox is enabled, shared memory backing ArrayBuffers must be
  119. // mapped into the sandbox address space. This custom SharedMemoryMapper
  120. // implements this.
  121. class ArrayBufferSharedMemoryMapper : public base::SharedMemoryMapper {
  122. public:
  123. absl::optional<base::span<uint8_t>> Map(
  124. base::subtle::PlatformSharedMemoryHandle handle,
  125. bool write_allowed,
  126. uint64_t offset,
  127. size_t size) override {
  128. v8::VirtualAddressSpace* address_space = v8::V8::GetSandboxAddressSpace();
  129. size_t allocation_granularity = address_space->allocation_granularity();
  130. v8::PlatformSharedMemoryHandle v8_handle;
  131. #if BUILDFLAG(IS_MAC)
  132. v8_handle = v8::SharedMemoryHandleFromMachMemoryEntry(handle);
  133. #elif BUILDFLAG(IS_FUCHSIA)
  134. v8_handle = v8::SharedMemoryHandleFromVMO(handle->get());
  135. #elif BUILDFLAG(IS_WIN)
  136. v8_handle = v8::SharedMemoryHandleFromFileMapping(handle);
  137. #elif BUILDFLAG(IS_ANDROID)
  138. v8_handle = v8::SharedMemoryHandleFromFileDescriptor(handle);
  139. #elif BUILDFLAG(IS_POSIX)
  140. v8_handle = v8::SharedMemoryHandleFromFileDescriptor(handle.fd);
  141. #else
  142. #error "Unknown platform"
  143. #endif
  144. // Size and offset must be a multiple of the page allocation granularity.
  145. // The caller already ensures that the offset is a multiple of the
  146. // allocation granularity though.
  147. CHECK_EQ(0UL, offset % allocation_granularity);
  148. size_t mapping_size = base::bits::AlignUp(size, allocation_granularity);
  149. v8::PagePermissions permissions = write_allowed
  150. ? v8::PagePermissions::kReadWrite
  151. : v8::PagePermissions::kRead;
  152. uintptr_t mapping = v8::V8::GetSandboxAddressSpace()->AllocateSharedPages(
  153. 0, mapping_size, permissions, v8_handle, offset);
  154. if (!mapping)
  155. return absl::nullopt;
  156. return base::make_span(reinterpret_cast<uint8_t*>(mapping), size);
  157. }
  158. void Unmap(base::span<uint8_t> mapping) override {
  159. v8::VirtualAddressSpace* address_space = v8::V8::GetSandboxAddressSpace();
  160. size_t allocation_granularity = address_space->allocation_granularity();
  161. uintptr_t address = reinterpret_cast<uintptr_t>(mapping.data());
  162. CHECK_EQ(0UL, address % allocation_granularity);
  163. size_t mapping_size =
  164. base::bits::AlignUp(mapping.size(), allocation_granularity);
  165. address_space->FreeSharedPages(address, mapping_size);
  166. }
  167. };
  168. #endif // V8_ENABLE_SANDBOX
  169. } // namespace
  170. base::SharedMemoryMapper* GetSharedMemoryMapperForArrayBuffers() {
  171. #if V8_ENABLE_SANDBOX
  172. static ArrayBufferSharedMemoryMapper instance;
  173. return &instance;
  174. #else
  175. return base::SharedMemoryMapper::GetDefaultInstance();
  176. #endif
  177. }
  178. } // namespace gin