src: prepare for v8 sandboxing · nodejs/node@08615b1

@@ -34,6 +34,8 @@ using ncrypto::EnginePointer;

3434

using ncrypto::SSLPointer;

3535

using v8::ArrayBuffer;

3636

using v8::BackingStore;

37+

using v8::BackingStoreInitializationMode;

38+

using v8::BackingStoreOnFailureMode;

3739

using v8::BigInt;

3840

using v8::Context;

3941

using v8::EscapableHandleScope;

@@ -339,16 +341,37 @@ ByteSource& ByteSource::operator=(ByteSource&& other) noexcept {

339341

return *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.

345348

CHECK_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_,

348370

size(),

349371

[](void* data, size_t length, void* deleter_data) {

350372

OPENSSL_clear_free(deleter_data, length);

351373

}, allocated_data_);

374+

#endif // V8_ENABLE_SANDBOX

352375

CHECK(ptr);

353376

allocated_data_ = nullptr;

354377

data_ = nullptr;

@@ -357,7 +380,7 @@ std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore() {

357380

}

358381359382

Local<ArrayBuffer> ByteSource::ToArrayBuffer(Environment* env) {

360-

std::unique_ptr<BackingStore> store = ReleaseToBackingStore();

383+

std::unique_ptr<BackingStore> store = ReleaseToBackingStore(env);

361384

return 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.

650673

void 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());

653687

uint32_t len = args[0].As<Uint32>()->Value();

654688655689

auto 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

}

680715681716

void SecureHeapUsed(const FunctionCallbackInfo<Value>& args) {