GeezerVison is showing github.com — src: prepare for v8 sandboxing · nodejs/node@08615b1
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: src/crypto/crypto_dh.cc +17Lines changed: 17 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -22,6 +22,8 @@ using ncrypto::DHPointer; | 22 | 22 | using ncrypto::EVPKeyCtxPointer; | 23 | 23 | using ncrypto::EVPKeyPointer; | 24 | 24 | using v8::ArrayBuffer; | | 25 | +using v8::BackingStoreInitializationMode; | | 26 | +using v8::BackingStoreOnFailureMode; | 25 | 27 | using v8::ConstructorBehavior; | 26 | 28 | using v8::Context; | 27 | 29 | using v8::DontDelete; | @@ -58,6 +60,20 @@ MaybeLocal<Value> DataPointerToBuffer(Environment* env, DataPointer&& data) { | 58 | 60 | struct Flag { | 59 | 61 | bool secure; | 60 | 62 | }; | | 63 | +#ifdef V8_ENABLE_SANDBOX | | 64 | + auto backing = ArrayBuffer::NewBackingStore( | | 65 | + env->isolate(), | | 66 | + data.size(), | | 67 | + BackingStoreInitializationMode::kUninitialized, | | 68 | + BackingStoreOnFailureMode::kReturnNull); | | 69 | + if (!backing) { | | 70 | + THROW_ERR_MEMORY_ALLOCATION_FAILED(env); | | 71 | + return MaybeLocal<Value>(); | | 72 | + } | | 73 | + if (data.size() > 0) { | | 74 | + memcpy(backing->Data(), data.get(), data.size()); | | 75 | + } | | 76 | +#else | 61 | 77 | auto backing = ArrayBuffer::NewBackingStore( | 62 | 78 | data.get(), | 63 | 79 | data.size(), | @@ -67,6 +83,7 @@ MaybeLocal<Value> DataPointerToBuffer(Environment* env, DataPointer&& data) { | 67 | 83 | }, | 68 | 84 | new Flag{data.isSecure()}); | 69 | 85 | data.release(); | | 86 | +#endif // V8_ENABLE_SANDBOX | 70 | 87 |
| 71 | 88 | auto ab = ArrayBuffer::New(env->isolate(), std::move(backing)); | 72 | 89 | return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Value>()); | |
Collapse file Copy file name to clipboardExpand all lines: src/crypto/crypto_util.cc +38-3Lines changed: 38 additions & 3 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -34,6 +34,8 @@ using ncrypto::EnginePointer; | 34 | 34 | using ncrypto::SSLPointer; | 35 | 35 | using v8::ArrayBuffer; | 36 | 36 | using v8::BackingStore; | | 37 | +using v8::BackingStoreInitializationMode; | | 38 | +using v8::BackingStoreOnFailureMode; | 37 | 39 | using v8::BigInt; | 38 | 40 | using v8::Context; | 39 | 41 | using v8::EscapableHandleScope; | @@ -339,16 +341,37 @@ ByteSource& ByteSource::operator=(ByteSource&& other) noexcept { | 339 | 341 | return *this; | 340 | 342 | } | 341 | 343 |
| 342 | | -std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore() { | | 344 | +std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore( | | 345 | + Environment* env) { | 343 | 346 | // It's ok for allocated_data_ to be nullptr but | 344 | 347 | // only if size_ is zero. | 345 | 348 | 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 | 346 | 368 | std::unique_ptr<BackingStore> ptr = ArrayBuffer::NewBackingStore( | 347 | 369 | allocated_data_, | 348 | 370 | size(), | 349 | 371 | [](void* data, size_t length, void* deleter_data) { | 350 | 372 | OPENSSL_clear_free(deleter_data, length); | 351 | 373 | }, allocated_data_); | | 374 | +#endif // V8_ENABLE_SANDBOX | 352 | 375 | CHECK(ptr); | 353 | 376 | allocated_data_ = nullptr; | 354 | 377 | data_ = nullptr; | @@ -357,7 +380,7 @@ std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore() { | 357 | 380 | } | 358 | 381 |
| 359 | 382 | Local<ArrayBuffer> ByteSource::ToArrayBuffer(Environment* env) { | 360 | | - std::unique_ptr<BackingStore> store = ReleaseToBackingStore(); | | 383 | + std::unique_ptr<BackingStore> store = ReleaseToBackingStore(env); | 361 | 384 | return ArrayBuffer::New(env->isolate(), std::move(store)); | 362 | 385 | } | 363 | 386 |
| @@ -648,8 +671,19 @@ namespace { | 648 | 671 | // using OPENSSL_malloc. However, if the secure heap is | 649 | 672 | // initialized, SecureBuffer will automatically use it. | 650 | 673 | void SecureBuffer(const FunctionCallbackInfo<Value>& args) { | 651 | | - CHECK(args[0]->IsUint32()); | 652 | 674 | 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()); | 653 | 687 | uint32_t len = args[0].As<Uint32>()->Value(); | 654 | 688 |
| 655 | 689 | auto data = DataPointer::SecureAlloc(len); | @@ -676,6 +710,7 @@ void SecureBuffer(const FunctionCallbackInfo<Value>& args) { | 676 | 710 |
| 677 | 711 | Local<ArrayBuffer> buffer = ArrayBuffer::New(env->isolate(), store); | 678 | 712 | args.GetReturnValue().Set(Uint8Array::New(buffer, 0, len)); | | 713 | +#endif // V8_ENABLE_SANDBOX | 679 | 714 | } | 680 | 715 |
| 681 | 716 | void SecureHeapUsed(const FunctionCallbackInfo<Value>& args) { | |
Collapse file Copy file name to clipboardExpand all lines: src/crypto/crypto_util.h +1-1Lines changed: 1 addition & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -185,7 +185,7 @@ class ByteSource final { | 185 | 185 | // Creates a v8::BackingStore that takes over responsibility for | 186 | 186 | // any allocated data. The ByteSource will be reset with size = 0 | 187 | 187 | // after being called. | 188 | | - std::unique_ptr<v8::BackingStore> ReleaseToBackingStore(); | | 188 | + std::unique_ptr<v8::BackingStore> ReleaseToBackingStore(Environment* env); | 189 | 189 |
| 190 | 190 | v8::Local<v8::ArrayBuffer> ToArrayBuffer(Environment* env); | 191 | 191 |
| |
Collapse file Copy file name to clipboardExpand all lines: src/crypto/crypto_x509.cc +17Lines changed: 17 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -29,6 +29,7 @@ using v8::Array; | 29 | 29 | using v8::ArrayBuffer; | 30 | 30 | using v8::ArrayBufferView; | 31 | 31 | using v8::BackingStoreInitializationMode; | | 32 | +using v8::BackingStoreOnFailureMode; | 32 | 33 | using v8::Boolean; | 33 | 34 | using v8::Context; | 34 | 35 | using v8::Date; | @@ -131,13 +132,29 @@ MaybeLocal<Value> ToBuffer(Environment* env, BIOPointer* bio) { | 131 | 132 | if (bio == nullptr || !*bio) [[unlikely]] | 132 | 133 | return {}; | 133 | 134 | BUF_MEM* mem = *bio; | | 135 | +#ifdef V8_ENABLE_SANDBOX | | 136 | + // If the v8 sandbox is enabled, then all array buffers must be allocated | | 137 | + // via the isolate. External buffers are not allowed. So, instead of wrapping | | 138 | + // the BIOPointer we'll copy it instead. | | 139 | + auto backing = ArrayBuffer::NewBackingStore( | | 140 | + env->isolate(), | | 141 | + mem->length, | | 142 | + BackingStoreInitializationMode::kUninitialized, | | 143 | + BackingStoreOnFailureMode::kReturnNull); | | 144 | + if (!backing) { | | 145 | + THROW_ERR_MEMORY_ALLOCATION_FAILED(env); | | 146 | + return MaybeLocal<Value>(); | | 147 | + } | | 148 | + memcpy(backing->Data(), mem->data, mem->length); | | 149 | +#else | 134 | 150 | auto backing = ArrayBuffer::NewBackingStore( | 135 | 151 | mem->data, | 136 | 152 | mem->length, | 137 | 153 | [](void*, size_t, void* data) { | 138 | 154 | BIOPointer free_me(static_cast<BIO*>(data)); | 139 | 155 | }, | 140 | 156 | bio->release()); | | 157 | +#endif // V8_ENABLE_SANDBOX | 141 | 158 | auto ab = ArrayBuffer::New(env->isolate(), std::move(backing)); | 142 | 159 | Local<Value> ret; | 143 | 160 | if (!Buffer::New(env, ab, 0, ab->ByteLength()).ToLocal(&ret)) return {}; | |
Collapse file Copy file name to clipboardExpand all lines: src/js_native_api_v8.cc +1-1Lines changed: 1 addition & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -114,7 +114,7 @@ napi_status NewExternalString(napi_env env, | 114 | 114 | CHECK_NEW_STRING_ARGS(env, str, length, result); | 115 | 115 |
| 116 | 116 | napi_status status; | 117 | | -#if defined(V8_ENABLE_SANDBOX) | | 117 | +#ifdef V8_ENABLE_SANDBOX | 118 | 118 | status = create_api(env, str, length, result); | 119 | 119 | if (status == napi_ok) { | 120 | 120 | if (copied != nullptr) { | |
Collapse file Copy file name to clipboardExpand all lines: src/node_api.cc +2-2Lines changed: 2 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -1056,9 +1056,9 @@ napi_create_external_buffer(napi_env env, | 1056 | 1056 | NAPI_PREAMBLE(env); | 1057 | 1057 | CHECK_ARG(env, result); | 1058 | 1058 |
| 1059 | | -#if defined(V8_ENABLE_SANDBOX) | | 1059 | +#ifdef V8_ENABLE_SANDBOX | 1060 | 1060 | return napi_set_last_error(env, napi_no_external_buffers_allowed); | 1061 | | -#endif | | 1061 | +#endif // V8_ENABLE_SANDBOX | 1062 | 1062 |
| 1063 | 1063 | v8::Isolate* isolate = env->isolate; | 1064 | 1064 |
| |
Collapse file Copy file name to clipboardExpand all lines: src/node_options.cc +5Lines changed: 5 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -81,6 +81,8 @@ void PerProcessOptions::CheckOptions(std::vector<std::string>* errors, | 81 | 81 | } | 82 | 82 |
| 83 | 83 | // 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. | 84 | 86 | if (secure_heap >= 2) { | 85 | 87 | if ((secure_heap & (secure_heap - 1)) != 0) | 86 | 88 | errors->push_back("--secure-heap must be a power of 2"); | @@ -93,6 +95,7 @@ void PerProcessOptions::CheckOptions(std::vector<std::string>* errors, | 93 | 95 | if ((secure_heap_min & (secure_heap_min - 1)) != 0) | 94 | 96 | errors->push_back("--secure-heap-min must be a power of 2"); | 95 | 97 | } | | 98 | +#endif // V8_ENABLE_SANDBOX | 96 | 99 | #endif // HAVE_OPENSSL | 97 | 100 |
| 98 | 101 | if (use_largepages != "off" && | @@ -1173,6 +1176,7 @@ PerProcessOptionsParser::PerProcessOptionsParser( | 1173 | 1176 | "force FIPS crypto (cannot be disabled)", | 1174 | 1177 | &PerProcessOptions::force_fips_crypto, | 1175 | 1178 | kAllowedInEnvvar); | | 1179 | +#ifndef V8_ENABLE_SANDBOX | 1176 | 1180 | AddOption("--secure-heap", | 1177 | 1181 | "total size of the OpenSSL secure heap", | 1178 | 1182 | &PerProcessOptions::secure_heap, | @@ -1181,6 +1185,7 @@ PerProcessOptionsParser::PerProcessOptionsParser( | 1181 | 1185 | "minimum allocation size from the OpenSSL secure heap", | 1182 | 1186 | &PerProcessOptions::secure_heap_min, | 1183 | 1187 | kAllowedInEnvvar); | | 1188 | +#endif // V8_ENABLE_SANDBOX | 1184 | 1189 | #endif // HAVE_OPENSSL | 1185 | 1190 | #if OPENSSL_VERSION_MAJOR >= 3 | 1186 | 1191 | AddOption("--openssl-legacy-provider", | |
|