Skip to content

Commit d9af9b2

Browse files
committed
src: prepare for v8 sandboxing
1 parent 9eb9c26 commit d9af9b2

7 files changed

+61
-7
lines changed

src/crypto/crypto_dh.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ using ncrypto::DHPointer;
2222
using ncrypto::EVPKeyCtxPointer;
2323
using ncrypto::EVPKeyPointer;
2424
using v8::ArrayBuffer;
25+
using v8::BackingStoreInitializationMode;
2526
using v8::ConstructorBehavior;
2627
using v8::Context;
2728
using v8::DontDelete;
@@ -58,6 +59,15 @@ MaybeLocal<Value> DataPointerToBuffer(Environment* env, DataPointer&& data) {
5859
struct Flag {
5960
bool secure;
6061
};
62+
#ifdef V8_ENABLE_SANDBOX
63+
auto backing = ArrayBuffer::NewBackingStore(
64+
env->isolate(),
65+
data.size(),
66+
BackingStoreInitializationMode::kUninitialized);
67+
if (data.size() > 0) {
68+
memcpy(backing->Data(), data.get(), data.size());
69+
}
70+
#else
6171
auto backing = ArrayBuffer::NewBackingStore(
6272
data.get(),
6373
data.size(),
@@ -67,6 +77,7 @@ MaybeLocal<Value> DataPointerToBuffer(Environment* env, DataPointer&& data) {
6777
},
6878
new Flag{data.isSecure()});
6979
data.release();
80+
#endif // V8_ENABLE_SANDBOX
7081

7182
auto ab = ArrayBuffer::New(env->isolate(), std::move(backing));
7283
return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Value>());

src/crypto/crypto_util.cc

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ using ncrypto::EnginePointer;
3434
using ncrypto::SSLPointer;
3535
using v8::ArrayBuffer;
3636
using v8::BackingStore;
37+
using v8::BackingStoreInitializationMode;
3738
using v8::BigInt;
3839
using v8::Context;
3940
using v8::EscapableHandleScope;
@@ -339,16 +340,30 @@ ByteSource& ByteSource::operator=(ByteSource&& other) noexcept {
339340
return *this;
340341
}
341342

342-
std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore() {
343+
std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore(
344+
Environment* env) {
343345
// It's ok for allocated_data_ to be nullptr but
344346
// only if size_ is zero.
345347
CHECK_IMPLIES(size_ > 0, allocated_data_ != nullptr);
348+
#ifdef V8_ENABLE_SANDBOX
349+
// If the v8 sandbox is enabled, then all array buffers must be allocated
350+
// via the isolate. External buffers are not allowed. So, instead of wrapping
351+
// the allocated data we'll copy it instead.
352+
353+
// TODO(@jasnell): It would be nice to use an abstracted utility to do this
354+
// branch instead of duplicating the V8_ENABLE_SANDBOX check each time.
355+
std::unique_ptr<BackingStore> ptr = ArrayBuffer::NewBackingStore(
356+
env->isolate(), size(), BackingStoreInitializationMode::kUninitialized);
357+
memcpy(ptr->Data(), allocated_data_, size());
358+
OPENSSL_clear_free(allocated_data_, size_);
359+
#else
346360
std::unique_ptr<BackingStore> ptr = ArrayBuffer::NewBackingStore(
347361
allocated_data_,
348362
size(),
349363
[](void* data, size_t length, void* deleter_data) {
350364
OPENSSL_clear_free(deleter_data, length);
351365
}, allocated_data_);
366+
#endif // V8_ENABLE_SANDBOX
352367
CHECK(ptr);
353368
allocated_data_ = nullptr;
354369
data_ = nullptr;
@@ -357,7 +372,7 @@ std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore() {
357372
}
358373

359374
Local<ArrayBuffer> ByteSource::ToArrayBuffer(Environment* env) {
360-
std::unique_ptr<BackingStore> store = ReleaseToBackingStore();
375+
std::unique_ptr<BackingStore> store = ReleaseToBackingStore(env);
361376
return ArrayBuffer::New(env->isolate(), std::move(store));
362377
}
363378

@@ -648,8 +663,19 @@ namespace {
648663
// using OPENSSL_malloc. However, if the secure heap is
649664
// initialized, SecureBuffer will automatically use it.
650665
void SecureBuffer(const FunctionCallbackInfo<Value>& args) {
651-
CHECK(args[0]->IsUint32());
652666
Environment* env = Environment::GetCurrent(args);
667+
#ifdef V8_ENABLE_SANDBOX
668+
// The v8 sandbox is enabled, so we cannot use the secure heap because
669+
// the sandbox requires that all array buffers be allocated via the isolate.
670+
// That is fundamentally incompatible with the secure heap which allocates
671+
// in openssl's secure heap area. Instead we'll just throw an error here.
672+
//
673+
// That said, we really shouldn't get here in the first place since the
674+
// option to enable the secure heap is only available when the sandbox
675+
// is disabled.
676+
THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(env);
677+
#else
678+
CHECK(args[0]->IsUint32());
653679
uint32_t len = args[0].As<Uint32>()->Value();
654680

655681
auto data = DataPointer::SecureAlloc(len);
@@ -676,6 +702,7 @@ void SecureBuffer(const FunctionCallbackInfo<Value>& args) {
676702

677703
Local<ArrayBuffer> buffer = ArrayBuffer::New(env->isolate(), store);
678704
args.GetReturnValue().Set(Uint8Array::New(buffer, 0, len));
705+
#endif // V8_ENABLE_SANDBOX
679706
}
680707

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

src/crypto/crypto_util.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ class ByteSource final {
185185
// Creates a v8::BackingStore that takes over responsibility for
186186
// any allocated data. The ByteSource will be reset with size = 0
187187
// after being called.
188-
std::unique_ptr<v8::BackingStore> ReleaseToBackingStore();
188+
std::unique_ptr<v8::BackingStore> ReleaseToBackingStore(Environment* env);
189189

190190
v8::Local<v8::ArrayBuffer> ToArrayBuffer(Environment* env);
191191

src/crypto/crypto_x509.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,24 @@ MaybeLocal<Value> ToBuffer(Environment* env, BIOPointer* bio) {
131131
if (bio == nullptr || !*bio) [[unlikely]]
132132
return {};
133133
BUF_MEM* mem = *bio;
134+
#ifdef V8_ENABLE_SANDBOX
135+
// If the v8 sandbox is enabled, then all array buffers must be allocated
136+
// via the isolate. External buffers are not allowed. So, instead of wrapping
137+
// the BIOPointer we'll copy it instead.
138+
auto backing = ArrayBuffer::NewBackingStore(
139+
env->isolate(),
140+
mem->length,
141+
BackingStoreInitializationMode::kUninitialized);
142+
memcpy(backing->Data(), mem->data, mem->length);
143+
#else
134144
auto backing = ArrayBuffer::NewBackingStore(
135145
mem->data,
136146
mem->length,
137147
[](void*, size_t, void* data) {
138148
BIOPointer free_me(static_cast<BIO*>(data));
139149
},
140150
bio->release());
151+
#endif // V8_ENABLE_SANDBOX
141152
auto ab = ArrayBuffer::New(env->isolate(), std::move(backing));
142153
Local<Value> ret;
143154
if (!Buffer::New(env, ab, 0, ab->ByteLength()).ToLocal(&ret)) return {};

src/js_native_api_v8.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ napi_status NewExternalString(napi_env env,
114114
CHECK_NEW_STRING_ARGS(env, str, length, result);
115115

116116
napi_status status;
117-
#if defined(V8_ENABLE_SANDBOX)
117+
#ifdef V8_ENABLE_SANDBOX
118118
status = create_api(env, str, length, result);
119119
if (status == napi_ok) {
120120
if (copied != nullptr) {

src/node_api.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,9 +1056,9 @@ napi_create_external_buffer(napi_env env,
10561056
NAPI_PREAMBLE(env);
10571057
CHECK_ARG(env, result);
10581058

1059-
#if defined(V8_ENABLE_SANDBOX)
1059+
#ifdef V8_ENABLE_SANDBOX
10601060
return napi_set_last_error(env, napi_no_external_buffers_allowed);
1061-
#endif
1061+
#endif // V8_ENABLE_SANDBOX
10621062

10631063
v8::Isolate* isolate = env->isolate;
10641064

src/node_options.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ void PerProcessOptions::CheckOptions(std::vector<std::string>* errors,
8181
}
8282

8383
// Any value less than 2 disables use of the secure heap.
84+
#ifndef V8_ENABLE_SANDBOX
85+
// The secure heap is not supported when V8_ENABLE_SANDBOX is enabled.
8486
if (secure_heap >= 2) {
8587
if ((secure_heap & (secure_heap - 1)) != 0)
8688
errors->push_back("--secure-heap must be a power of 2");
@@ -93,6 +95,7 @@ void PerProcessOptions::CheckOptions(std::vector<std::string>* errors,
9395
if ((secure_heap_min & (secure_heap_min - 1)) != 0)
9496
errors->push_back("--secure-heap-min must be a power of 2");
9597
}
98+
#endif // V8_ENABLE_SANDBOX
9699
#endif // HAVE_OPENSSL
97100

98101
if (use_largepages != "off" &&
@@ -1172,6 +1175,7 @@ PerProcessOptionsParser::PerProcessOptionsParser(
11721175
"force FIPS crypto (cannot be disabled)",
11731176
&PerProcessOptions::force_fips_crypto,
11741177
kAllowedInEnvvar);
1178+
#ifndef V8_ENABLE_SANDBOX
11751179
AddOption("--secure-heap",
11761180
"total size of the OpenSSL secure heap",
11771181
&PerProcessOptions::secure_heap,
@@ -1180,6 +1184,7 @@ PerProcessOptionsParser::PerProcessOptionsParser(
11801184
"minimum allocation size from the OpenSSL secure heap",
11811185
&PerProcessOptions::secure_heap_min,
11821186
kAllowedInEnvvar);
1187+
#endif // V8_ENABLE_SANDBOX
11831188
#endif // HAVE_OPENSSL
11841189
#if OPENSSL_VERSION_MAJOR >= 3
11851190
AddOption("--openssl-legacy-provider",

0 commit comments

Comments
 (0)