* chore: bump node in DEPS to v22.14.0 * src: move more crypto impl detail to ncrypto dep https://github.com/nodejs/node/pull/56421 * test: move crypto related common utilities in common/crypto https://github.com/nodejs/node/pull/56714 * module: add findPackageJSON util https://github.com/nodejs/node/pull/55412 * module: mark evaluation rejection in require(esm) as handled https://github.com/nodejs/node/pull/56122 * chore: fixup patch indices * deps: move inspector_protocol to deps https://github.com/nodejs/node/pull/56649 * fixup! src: move more crypto impl detail to ncrypto dep * fixup! deps: move inspector_protocol to deps * fixup! src: move more crypto impl detail to ncrypto dep * crypto: fix checkPrime crash with large buffers https://github.com/nodejs/node/pull/56559 * tls: fix error stack conversion in cryptoErrorListToException() https://github.com/nodejs/node/pull/56554 * module: add findPackageJSON util https://github.com/nodejs/node/pull/55412 Our revert of native legacyMainResolve makes this very difficult to make work, so disable for now. * lib: add typescript support to STDIN eval https://github.com/nodejs/node/pull/56359 * chore: fix patch --------- Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com> Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
		
			
				
	
	
		
			401 lines
		
	
	
	
		
			16 KiB
			
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			401 lines
		
	
	
	
		
			16 KiB
			
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 | 
						|
From: Jeremy Rose <japthorp@slack-corp.com>
 | 
						|
Date: Tue, 21 Jun 2022 10:04:21 -0700
 | 
						|
Subject: support V8 sandboxed pointers
 | 
						|
 | 
						|
This refactors several allocators to allocate within the V8 memory cage,
 | 
						|
allowing them to be compatible with the V8_SANDBOXED_POINTERS feature.
 | 
						|
 | 
						|
diff --git a/src/api/environment.cc b/src/api/environment.cc
 | 
						|
index ad323fc800a33c010b0504a4aa55c107498dee26..fc9b056d2f7e25109100fbde5f3ab0aebc8c619a 100644
 | 
						|
--- a/src/api/environment.cc
 | 
						|
+++ b/src/api/environment.cc
 | 
						|
@@ -102,6 +102,14 @@ MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
 | 
						|
   return result;
 | 
						|
 }
 | 
						|
 
 | 
						|
+NodeArrayBufferAllocator::NodeArrayBufferAllocator() {
 | 
						|
+  zero_fill_field_ = static_cast<uint32_t*>(allocator_->Allocate(sizeof(*zero_fill_field_)));
 | 
						|
+}
 | 
						|
+
 | 
						|
+NodeArrayBufferAllocator::~NodeArrayBufferAllocator() {
 | 
						|
+  allocator_->Free(zero_fill_field_, sizeof(*zero_fill_field_));
 | 
						|
+}
 | 
						|
+
 | 
						|
 void* NodeArrayBufferAllocator::Allocate(size_t size) {
 | 
						|
   void* ret;
 | 
						|
   if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
 | 
						|
diff --git a/src/crypto/crypto_dh.cc b/src/crypto/crypto_dh.cc
 | 
						|
index 5387d9625a28bb7d11f7f0f05a5f07d1fee2c216..1b3b8c7b70073926f8dbf02759c2e1af5d938679 100644
 | 
						|
--- a/src/crypto/crypto_dh.cc
 | 
						|
+++ b/src/crypto/crypto_dh.cc
 | 
						|
@@ -55,13 +55,32 @@ void DiffieHellman::MemoryInfo(MemoryTracker* tracker) const {
 | 
						|
 
 | 
						|
 namespace {
 | 
						|
 MaybeLocal<Value> DataPointerToBuffer(Environment* env, DataPointer&& data) {
 | 
						|
+#if defined(V8_ENABLE_SANDBOX)
 | 
						|
+  std::unique_ptr<v8::BackingStore> backing;
 | 
						|
+  if (data.size() > 0) {
 | 
						|
+    std::unique_ptr<ArrayBuffer::Allocator> allocator(ArrayBuffer::Allocator::NewDefaultAllocator());
 | 
						|
+    void* v8_data = allocator->Allocate(data.size());
 | 
						|
+    CHECK(v8_data);
 | 
						|
+    memcpy(v8_data, data.get(), data.size());
 | 
						|
+    backing = ArrayBuffer::NewBackingStore(
 | 
						|
+        v8_data,
 | 
						|
+        data.size(),
 | 
						|
+        [](void* data, size_t length, void*) {
 | 
						|
+          std::unique_ptr<ArrayBuffer::Allocator> allocator(ArrayBuffer::Allocator::NewDefaultAllocator());
 | 
						|
+          allocator->Free(data, length);
 | 
						|
+        }, nullptr);
 | 
						|
+  } else {
 | 
						|
+    NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
 | 
						|
+    backing = v8::ArrayBuffer::NewBackingStore(env->isolate(), data.size());
 | 
						|
+  }
 | 
						|
+#else
 | 
						|
   auto backing = ArrayBuffer::NewBackingStore(
 | 
						|
       data.get(),
 | 
						|
       data.size(),
 | 
						|
       [](void* data, size_t len, void* ptr) { DataPointer free_me(data, len); },
 | 
						|
       nullptr);
 | 
						|
   data.release();
 | 
						|
-
 | 
						|
+#endif
 | 
						|
   auto ab = ArrayBuffer::New(env->isolate(), std::move(backing));
 | 
						|
   return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Value>());
 | 
						|
 }
 | 
						|
diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc
 | 
						|
index 25fa9af8153852f49d5289aa253f3c8f7268d89c..a67268f78b18cf71b90b9e31ad733eb0c8d93af3 100644
 | 
						|
--- a/src/crypto/crypto_util.cc
 | 
						|
+++ b/src/crypto/crypto_util.cc
 | 
						|
@@ -335,10 +335,35 @@ ByteSource& ByteSource::operator=(ByteSource&& other) noexcept {
 | 
						|
   return *this;
 | 
						|
 }
 | 
						|
 
 | 
						|
-std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore() {
 | 
						|
+std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore(Environment* env) {
 | 
						|
   // It's ok for allocated_data_ to be nullptr but
 | 
						|
   // only if size_ is zero.
 | 
						|
   CHECK_IMPLIES(size_ > 0, allocated_data_ != nullptr);
 | 
						|
+#if defined(V8_ENABLE_SANDBOX)
 | 
						|
+  // When V8 sandboxed pointers are enabled, we have to copy into the memory
 | 
						|
+  // cage. We still want to ensure we erase the data on free though, so
 | 
						|
+  // provide a custom deleter that calls OPENSSL_cleanse.
 | 
						|
+  if (!size())
 | 
						|
+    return ArrayBuffer::NewBackingStore(env->isolate(), 0);
 | 
						|
+  std::unique_ptr<ArrayBuffer::Allocator> allocator(ArrayBuffer::Allocator::NewDefaultAllocator());
 | 
						|
+  void* v8_data = allocator->Allocate(size());
 | 
						|
+  CHECK(v8_data);
 | 
						|
+  memcpy(v8_data, allocated_data_, size());
 | 
						|
+  OPENSSL_clear_free(allocated_data_, size());
 | 
						|
+  std::unique_ptr<BackingStore> ptr = ArrayBuffer::NewBackingStore(
 | 
						|
+      v8_data,
 | 
						|
+      size(),
 | 
						|
+      [](void* data, size_t length, void*) {
 | 
						|
+        OPENSSL_cleanse(data, length);
 | 
						|
+        std::unique_ptr<ArrayBuffer::Allocator> allocator(ArrayBuffer::Allocator::NewDefaultAllocator());
 | 
						|
+        allocator->Free(data, length);
 | 
						|
+      }, nullptr);
 | 
						|
+  CHECK(ptr);
 | 
						|
+  allocated_data_ = nullptr;
 | 
						|
+  data_ = nullptr;
 | 
						|
+  size_ = 0;
 | 
						|
+  return ptr;
 | 
						|
+#else
 | 
						|
   std::unique_ptr<BackingStore> ptr = ArrayBuffer::NewBackingStore(
 | 
						|
       allocated_data_,
 | 
						|
       size(),
 | 
						|
@@ -350,10 +375,11 @@ std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore() {
 | 
						|
   data_ = nullptr;
 | 
						|
   size_ = 0;
 | 
						|
   return ptr;
 | 
						|
+#endif  // defined(V8_ENABLE_SANDBOX)
 | 
						|
 }
 | 
						|
 
 | 
						|
 Local<ArrayBuffer> ByteSource::ToArrayBuffer(Environment* env) {
 | 
						|
-  std::unique_ptr<BackingStore> store = ReleaseToBackingStore();
 | 
						|
+  std::unique_ptr<BackingStore> store = ReleaseToBackingStore(env);
 | 
						|
   return ArrayBuffer::New(env->isolate(), std::move(store));
 | 
						|
 }
 | 
						|
 
 | 
						|
@@ -650,6 +676,16 @@ namespace {
 | 
						|
 // in which case this has the same semantics as
 | 
						|
 // using OPENSSL_malloc. However, if the secure heap is
 | 
						|
 // initialized, SecureBuffer will automatically use it.
 | 
						|
+#if defined(V8_ENABLE_SANDBOX)
 | 
						|
+// When V8 sandboxed pointers are enabled, the secure heap cannot be used as
 | 
						|
+// all ArrayBuffers must be allocated inside the V8 memory cage.
 | 
						|
+void SecureBuffer(const FunctionCallbackInfo<Value>& args) {
 | 
						|
+  CHECK(args[0]->IsUint32());
 | 
						|
+  uint32_t len = args[0].As<Uint32>()->Value();
 | 
						|
+  Local<ArrayBuffer> buffer = ArrayBuffer::New(args.GetIsolate(), len);
 | 
						|
+  args.GetReturnValue().Set(Uint8Array::New(buffer, 0, len));
 | 
						|
+}
 | 
						|
+#else
 | 
						|
 void SecureBuffer(const FunctionCallbackInfo<Value>& args) {
 | 
						|
   CHECK(args[0]->IsUint32());
 | 
						|
   Environment* env = Environment::GetCurrent(args);
 | 
						|
@@ -671,6 +707,7 @@ void SecureBuffer(const FunctionCallbackInfo<Value>& args) {
 | 
						|
   Local<ArrayBuffer> buffer = ArrayBuffer::New(env->isolate(), store);
 | 
						|
   args.GetReturnValue().Set(Uint8Array::New(buffer, 0, len));
 | 
						|
 }
 | 
						|
+#endif  // defined(V8_ENABLE_SANDBOX)
 | 
						|
 
 | 
						|
 void SecureHeapUsed(const FunctionCallbackInfo<Value>& args) {
 | 
						|
 #ifndef OPENSSL_IS_BORINGSSL
 | 
						|
diff --git a/src/crypto/crypto_util.h b/src/crypto/crypto_util.h
 | 
						|
index a5967c7d24b8365eb64ab63ec0b3ef8dc23c727e..2acebc3ac2ed9f631fc572f42f19f2e3dccfeb12 100644
 | 
						|
--- a/src/crypto/crypto_util.h
 | 
						|
+++ b/src/crypto/crypto_util.h
 | 
						|
@@ -241,7 +241,7 @@ class ByteSource {
 | 
						|
   // Creates a v8::BackingStore that takes over responsibility for
 | 
						|
   // any allocated data. The ByteSource will be reset with size = 0
 | 
						|
   // after being called.
 | 
						|
-  std::unique_ptr<v8::BackingStore> ReleaseToBackingStore();
 | 
						|
+  std::unique_ptr<v8::BackingStore> ReleaseToBackingStore(Environment* env);
 | 
						|
 
 | 
						|
   v8::Local<v8::ArrayBuffer> ToArrayBuffer(Environment* env);
 | 
						|
 
 | 
						|
diff --git a/src/crypto/crypto_x509.cc b/src/crypto/crypto_x509.cc
 | 
						|
index 3465454e4de4a78912b81e7eca0de395fbe89911..c8ae863460107c69dd77d67c76c11843114e99c4 100644
 | 
						|
--- a/src/crypto/crypto_x509.cc
 | 
						|
+++ b/src/crypto/crypto_x509.cc
 | 
						|
@@ -167,6 +167,19 @@ MaybeLocal<Value> ToV8Value(Local<Context> context, const BIOPointer& bio) {
 | 
						|
 MaybeLocal<Value> ToBuffer(Environment* env, BIOPointer* bio) {
 | 
						|
   if (bio == nullptr || !*bio) return {};
 | 
						|
   BUF_MEM* mem = *bio;
 | 
						|
+#if defined(V8_ENABLE_SANDBOX)
 | 
						|
+  std::unique_ptr<ArrayBuffer::Allocator> allocator(ArrayBuffer::Allocator::NewDefaultAllocator());
 | 
						|
+  void* v8_data = allocator->Allocate(mem->length);
 | 
						|
+  CHECK(v8_data);
 | 
						|
+  memcpy(v8_data, mem->data, mem->length);
 | 
						|
+  std::unique_ptr<v8::BackingStore> backing = ArrayBuffer::NewBackingStore(
 | 
						|
+      v8_data,
 | 
						|
+      mem->length,
 | 
						|
+      [](void* data, size_t length, void*) {
 | 
						|
+        std::unique_ptr<ArrayBuffer::Allocator> allocator(ArrayBuffer::Allocator::NewDefaultAllocator());
 | 
						|
+        allocator->Free(data, length);
 | 
						|
+      }, nullptr);
 | 
						|
+#else
 | 
						|
   auto backing = ArrayBuffer::NewBackingStore(
 | 
						|
       mem->data,
 | 
						|
       mem->length,
 | 
						|
@@ -174,6 +187,8 @@ MaybeLocal<Value> ToBuffer(Environment* env, BIOPointer* bio) {
 | 
						|
         BIOPointer free_me(static_cast<BIO*>(data));
 | 
						|
       },
 | 
						|
       bio->release());
 | 
						|
+#endif
 | 
						|
+
 | 
						|
   auto ab = ArrayBuffer::New(env->isolate(), std::move(backing));
 | 
						|
   Local<Value> ret;
 | 
						|
   if (!Buffer::New(env, ab, 0, ab->ByteLength()).ToLocal(&ret)) return {};
 | 
						|
diff --git a/src/node_i18n.cc b/src/node_i18n.cc
 | 
						|
index 0bcf10a0b35accb8d6d5fe9891d4f52b27d40346..606c2021242e6967ea4195af3e2493a7d5745dae 100644
 | 
						|
--- a/src/node_i18n.cc
 | 
						|
+++ b/src/node_i18n.cc
 | 
						|
@@ -104,7 +104,7 @@ namespace {
 | 
						|
 
 | 
						|
 template <typename T>
 | 
						|
 MaybeLocal<Object> ToBufferEndian(Environment* env, MaybeStackBuffer<T>* buf) {
 | 
						|
-  MaybeLocal<Object> ret = Buffer::New(env, buf);
 | 
						|
+  MaybeLocal<Object> ret = Buffer::Copy(env, reinterpret_cast<char*>(buf->out()), buf->length() * sizeof(T));
 | 
						|
   if (ret.IsEmpty())
 | 
						|
     return ret;
 | 
						|
 
 | 
						|
@@ -181,7 +181,7 @@ MaybeLocal<Object> TranscodeLatin1ToUcs2(Environment* env,
 | 
						|
     return {};
 | 
						|
   }
 | 
						|
 
 | 
						|
-  return Buffer::New(env, &destbuf);
 | 
						|
+  return Buffer::Copy(env, reinterpret_cast<char*>(destbuf.out()), destbuf.length() * sizeof(UChar));
 | 
						|
 }
 | 
						|
 
 | 
						|
 MaybeLocal<Object> TranscodeFromUcs2(Environment* env,
 | 
						|
@@ -226,7 +226,7 @@ MaybeLocal<Object> TranscodeUcs2FromUtf8(Environment* env,
 | 
						|
     return {};
 | 
						|
   }
 | 
						|
 
 | 
						|
-  return Buffer::New(env, &destbuf);
 | 
						|
+  return Buffer::Copy(env, reinterpret_cast<char*>(destbuf.out()), destbuf.length() * sizeof(UChar));
 | 
						|
 }
 | 
						|
 
 | 
						|
 MaybeLocal<Object> TranscodeUtf8FromUcs2(Environment* env,
 | 
						|
@@ -250,7 +250,7 @@ MaybeLocal<Object> TranscodeUtf8FromUcs2(Environment* env,
 | 
						|
     return {};
 | 
						|
   }
 | 
						|
 
 | 
						|
-  return Buffer::New(env, &destbuf);
 | 
						|
+  return Buffer::Copy(env, reinterpret_cast<char*>(destbuf.out()), destbuf.length() * sizeof(char));
 | 
						|
 }
 | 
						|
 
 | 
						|
 constexpr const char* EncodingName(const enum encoding encoding) {
 | 
						|
diff --git a/src/node_internals.h b/src/node_internals.h
 | 
						|
index 382df89a2312f76b5293412a8d51969ae5d9fa9c..1c90da9bbcb9547ab36de4d01088c03f3350b787 100644
 | 
						|
--- a/src/node_internals.h
 | 
						|
+++ b/src/node_internals.h
 | 
						|
@@ -117,7 +117,9 @@ v8::Maybe<void> InitializePrimordials(v8::Local<v8::Context> context);
 | 
						|
 
 | 
						|
 class NodeArrayBufferAllocator : public ArrayBufferAllocator {
 | 
						|
  public:
 | 
						|
-  inline uint32_t* zero_fill_field() { return &zero_fill_field_; }
 | 
						|
+  NodeArrayBufferAllocator();
 | 
						|
+  ~NodeArrayBufferAllocator() override;
 | 
						|
+  inline uint32_t* zero_fill_field() { return zero_fill_field_; }
 | 
						|
 
 | 
						|
   void* Allocate(size_t size) override;  // Defined in src/node.cc
 | 
						|
   void* AllocateUninitialized(size_t size) override;
 | 
						|
@@ -135,7 +137,7 @@ class NodeArrayBufferAllocator : public ArrayBufferAllocator {
 | 
						|
   }
 | 
						|
 
 | 
						|
  private:
 | 
						|
-  uint32_t zero_fill_field_ = 1;  // Boolean but exposed as uint32 to JS land.
 | 
						|
+  uint32_t* zero_fill_field_ = nullptr;  // Boolean but exposed as uint32 to JS land.
 | 
						|
   std::atomic<size_t> total_mem_usage_ {0};
 | 
						|
 
 | 
						|
   // Delegate to V8's allocator for compatibility with the V8 memory cage.
 | 
						|
diff --git a/src/node_serdes.cc b/src/node_serdes.cc
 | 
						|
index 7a70997bc024efa4f3ff4cabe30d5e88dcc7bc78..6552af3ed0acede41c1b16ef77eb359dc54f088a 100644
 | 
						|
--- a/src/node_serdes.cc
 | 
						|
+++ b/src/node_serdes.cc
 | 
						|
@@ -29,6 +29,26 @@ using v8::ValueSerializer;
 | 
						|
 
 | 
						|
 namespace serdes {
 | 
						|
 
 | 
						|
+v8::ArrayBuffer::Allocator* GetAllocator() {
 | 
						|
+  static v8::ArrayBuffer::Allocator* allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
 | 
						|
+  return allocator;
 | 
						|
+}
 | 
						|
+
 | 
						|
+void* Reallocate(void* data, size_t old_length,
 | 
						|
+                 size_t new_length) {
 | 
						|
+  if (old_length == new_length) return data;
 | 
						|
+  uint8_t* new_data =
 | 
						|
+      reinterpret_cast<uint8_t*>(GetAllocator()->AllocateUninitialized(new_length));
 | 
						|
+  if (new_data == nullptr) return nullptr;
 | 
						|
+  size_t bytes_to_copy = std::min(old_length, new_length);
 | 
						|
+  memcpy(new_data, data, bytes_to_copy);
 | 
						|
+  if (new_length > bytes_to_copy) {
 | 
						|
+    memset(new_data + bytes_to_copy, 0, new_length - bytes_to_copy);
 | 
						|
+  }
 | 
						|
+  GetAllocator()->Free(data, old_length);
 | 
						|
+  return new_data;
 | 
						|
+}
 | 
						|
+
 | 
						|
 class SerializerContext : public BaseObject,
 | 
						|
                           public ValueSerializer::Delegate {
 | 
						|
  public:
 | 
						|
@@ -37,10 +57,15 @@ class SerializerContext : public BaseObject,
 | 
						|
 
 | 
						|
   ~SerializerContext() override = default;
 | 
						|
 
 | 
						|
+  // v8::ValueSerializer::Delegate
 | 
						|
   void ThrowDataCloneError(Local<String> message) override;
 | 
						|
   Maybe<bool> WriteHostObject(Isolate* isolate, Local<Object> object) override;
 | 
						|
   Maybe<uint32_t> GetSharedArrayBufferId(
 | 
						|
       Isolate* isolate, Local<SharedArrayBuffer> shared_array_buffer) override;
 | 
						|
+  void* ReallocateBufferMemory(void* old_buffer,
 | 
						|
+                               size_t old_length,
 | 
						|
+                               size_t* new_length) override;
 | 
						|
+  void FreeBufferMemory(void* buffer) override;
 | 
						|
 
 | 
						|
   static void SetTreatArrayBufferViewsAsHostObjects(
 | 
						|
       const FunctionCallbackInfo<Value>& args);
 | 
						|
@@ -61,6 +86,7 @@ class SerializerContext : public BaseObject,
 | 
						|
 
 | 
						|
  private:
 | 
						|
   ValueSerializer serializer_;
 | 
						|
+  size_t last_length_ = 0;
 | 
						|
 };
 | 
						|
 
 | 
						|
 class DeserializerContext : public BaseObject,
 | 
						|
@@ -144,6 +170,24 @@ Maybe<uint32_t> SerializerContext::GetSharedArrayBufferId(
 | 
						|
   return id.ToLocalChecked()->Uint32Value(env()->context());
 | 
						|
 }
 | 
						|
 
 | 
						|
+void* SerializerContext::ReallocateBufferMemory(void* old_buffer,
 | 
						|
+                                                size_t requested_size,
 | 
						|
+                                                size_t* new_length) {
 | 
						|
+  *new_length = std::max(static_cast<size_t>(4096), requested_size);
 | 
						|
+  if (old_buffer) {
 | 
						|
+    void* ret = Reallocate(old_buffer, last_length_, *new_length);
 | 
						|
+    last_length_ = *new_length;
 | 
						|
+    return ret;
 | 
						|
+  } else {
 | 
						|
+    last_length_ = *new_length;
 | 
						|
+    return GetAllocator()->Allocate(*new_length);
 | 
						|
+  }
 | 
						|
+}
 | 
						|
+
 | 
						|
+void SerializerContext::FreeBufferMemory(void* buffer) {
 | 
						|
+  GetAllocator()->Free(buffer, last_length_);
 | 
						|
+}
 | 
						|
+
 | 
						|
 Maybe<bool> SerializerContext::WriteHostObject(Isolate* isolate,
 | 
						|
                                                Local<Object> input) {
 | 
						|
   MaybeLocal<Value> ret;
 | 
						|
@@ -209,9 +253,14 @@ void SerializerContext::ReleaseBuffer(const FunctionCallbackInfo<Value>& args) {
 | 
						|
   // Note: Both ValueSerializer and this Buffer::New() variant use malloc()
 | 
						|
   // as the underlying allocator.
 | 
						|
   std::pair<uint8_t*, size_t> ret = ctx->serializer_.Release();
 | 
						|
-  auto buf = Buffer::New(ctx->env(),
 | 
						|
-                         reinterpret_cast<char*>(ret.first),
 | 
						|
-                         ret.second);
 | 
						|
+  std::unique_ptr<v8::BackingStore> bs =
 | 
						|
+      v8::ArrayBuffer::NewBackingStore(reinterpret_cast<char*>(ret.first), ret.second,
 | 
						|
+        [](void* data, size_t length, void* deleter_data) {
 | 
						|
+          if (data) GetAllocator()->Free(reinterpret_cast<char*>(data), length);
 | 
						|
+        }, nullptr);
 | 
						|
+  Local<ArrayBuffer> ab = v8::ArrayBuffer::New(ctx->env()->isolate(), std::move(bs));
 | 
						|
+
 | 
						|
+  auto buf = Buffer::New(ctx->env(), ab, 0, ret.second);
 | 
						|
 
 | 
						|
   if (!buf.IsEmpty()) {
 | 
						|
     args.GetReturnValue().Set(buf.ToLocalChecked());
 | 
						|
diff --git a/src/node_trace_events.cc b/src/node_trace_events.cc
 | 
						|
index 9787b14352753c5e0f8dc2b90093680e7cd10f1a..31af9e62396368af1b81f8841a705fd313df2b9f 100644
 | 
						|
--- a/src/node_trace_events.cc
 | 
						|
+++ b/src/node_trace_events.cc
 | 
						|
@@ -132,12 +132,28 @@ static void GetCategoryEnabledBuffer(const FunctionCallbackInfo<Value>& args) {
 | 
						|
   const uint8_t* enabled_pointer =
 | 
						|
       TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_name.out());
 | 
						|
   uint8_t* enabled_pointer_cast = const_cast<uint8_t*>(enabled_pointer);
 | 
						|
+  uint8_t size = sizeof(*enabled_pointer_cast);
 | 
						|
 
 | 
						|
+#if defined(V8_ENABLE_SANDBOX)
 | 
						|
+  std::unique_ptr<ArrayBuffer::Allocator> allocator(ArrayBuffer::Allocator::NewDefaultAllocator());
 | 
						|
+  void* v8_data = allocator->Allocate(size);
 | 
						|
+  CHECK(v8_data);
 | 
						|
+  memcpy(v8_data, enabled_pointer_cast, size);
 | 
						|
+  std::unique_ptr<BackingStore> bs = ArrayBuffer::NewBackingStore(
 | 
						|
+      v8_data,
 | 
						|
+      size,
 | 
						|
+      [](void* data, size_t length, void*) {
 | 
						|
+        std::unique_ptr<ArrayBuffer::Allocator> allocator(ArrayBuffer::Allocator::NewDefaultAllocator());
 | 
						|
+        allocator->Free(data, length);
 | 
						|
+      }, nullptr);
 | 
						|
+#else
 | 
						|
   std::unique_ptr<BackingStore> bs = ArrayBuffer::NewBackingStore(
 | 
						|
       enabled_pointer_cast,
 | 
						|
-      sizeof(*enabled_pointer_cast),
 | 
						|
+      size,
 | 
						|
       [](void*, size_t, void*) {},
 | 
						|
       nullptr);
 | 
						|
+#endif
 | 
						|
+
 | 
						|
   auto ab = ArrayBuffer::New(isolate, std::move(bs));
 | 
						|
   v8::Local<Uint8Array> u8 = v8::Uint8Array::New(ab, 0, 1);
 | 
						|
 
 | 
						|
diff --git a/test/parallel/test-buffer-tostring-range.js b/test/parallel/test-buffer-tostring-range.js
 | 
						|
index 73fec107a36c3db4af6f492137d0ca174f2d0547..a1153ec381f7b12a1640b611073f6997e1ec5696 100644
 | 
						|
--- a/test/parallel/test-buffer-tostring-range.js
 | 
						|
+++ b/test/parallel/test-buffer-tostring-range.js
 | 
						|
@@ -102,8 +102,8 @@ assert.throws(() => {
 | 
						|
 // Must not throw when start and end are within kMaxLength
 | 
						|
 // Cannot test on 32bit machine as we are testing the case
 | 
						|
 // when start and end are above the threshold
 | 
						|
-if (!common.openSSLIsBoringSSL) {
 | 
						|
+/*
 | 
						|
 const threshold = 0xFFFFFFFF;
 | 
						|
 const largeBuffer = Buffer.alloc(threshold + 20);
 | 
						|
 largeBuffer.toString('utf8', threshold, threshold + 20);
 | 
						|
-}
 | 
						|
+*/
 |