src: prepare for v8 sandboxing · nodejs/node@08615b1
@@ -34,6 +34,8 @@ using ncrypto::EnginePointer;
3434using ncrypto::SSLPointer;
3535using v8::ArrayBuffer;
3636using v8::BackingStore;
37+using v8::BackingStoreInitializationMode;
38+using v8::BackingStoreOnFailureMode;
3739using v8::BigInt;
3840using v8::Context;
3941using v8::EscapableHandleScope;
@@ -339,16 +341,37 @@ ByteSource& ByteSource::operator=(ByteSource&& other) noexcept {
339341return *this;
340342}
341343342-std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore() {
344+std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore(
345+ Environment* env) {
343346// It's ok for allocated_data_ to be nullptr but
344347// only if size_ is zero.
345348CHECK_IMPLIES(size_ > 0, allocated_data_ != nullptr);
349+#ifdef V8_ENABLE_SANDBOX
350+// If the v8 sandbox is enabled, then all array buffers must be allocated
351+// via the isolate. External buffers are not allowed. So, instead of wrapping
352+// the allocated data we'll copy it instead.
353+354+// TODO(@jasnell): It would be nice to use an abstracted utility to do this
355+// branch instead of duplicating the V8_ENABLE_SANDBOX check each time.
356+ std::unique_ptr<BackingStore> ptr = ArrayBuffer::NewBackingStore(
357+ env->isolate(),
358+size(),
359+ BackingStoreInitializationMode::kUninitialized,
360+ BackingStoreOnFailureMode::kReturnNull);
361+if (!ptr) {
362+THROW_ERR_MEMORY_ALLOCATION_FAILED(env);
363+return nullptr;
364+ }
365+memcpy(ptr->Data(), allocated_data_, size());
366+OPENSSL_clear_free(allocated_data_, size_);
367+#else
346368 std::unique_ptr<BackingStore> ptr = ArrayBuffer::NewBackingStore(
347369 allocated_data_,
348370size(),
349371 [](void* data, size_t length, void* deleter_data) {
350372OPENSSL_clear_free(deleter_data, length);
351373 }, allocated_data_);
374+#endif // V8_ENABLE_SANDBOX
352375CHECK(ptr);
353376 allocated_data_ = nullptr;
354377 data_ = nullptr;
@@ -357,7 +380,7 @@ std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore() {
357380}
358381359382Local<ArrayBuffer> ByteSource::ToArrayBuffer(Environment* env) {
360- std::unique_ptr<BackingStore> store = ReleaseToBackingStore();
383+ std::unique_ptr<BackingStore> store = ReleaseToBackingStore(env);
361384return ArrayBuffer::New(env->isolate(), std::move(store));
362385}
363386@@ -648,8 +671,19 @@ namespace {
648671// using OPENSSL_malloc. However, if the secure heap is
649672// initialized, SecureBuffer will automatically use it.
650673void SecureBuffer(const FunctionCallbackInfo<Value>& args) {
651-CHECK(args[0]->IsUint32());
652674 Environment* env = Environment::GetCurrent(args);
675+#ifdef V8_ENABLE_SANDBOX
676+// The v8 sandbox is enabled, so we cannot use the secure heap because
677+// the sandbox requires that all array buffers be allocated via the isolate.
678+// That is fundamentally incompatible with the secure heap which allocates
679+// in openssl's secure heap area. Instead we'll just throw an error here.
680+//
681+// That said, we really shouldn't get here in the first place since the
682+// option to enable the secure heap is only available when the sandbox
683+// is disabled.
684+UNREACHABLE();
685+#else
686+CHECK(args[0]->IsUint32());
653687uint32_t len = args[0].As<Uint32>()->Value();
654688655689auto data = DataPointer::SecureAlloc(len);
@@ -676,6 +710,7 @@ void SecureBuffer(const FunctionCallbackInfo<Value>& args) {
676710677711 Local<ArrayBuffer> buffer = ArrayBuffer::New(env->isolate(), store);
678712 args.GetReturnValue().Set(Uint8Array::New(buffer, 0, len));
713+#endif // V8_ENABLE_SANDBOX
679714}
680715681716void SecureHeapUsed(const FunctionCallbackInfo<Value>& args) {