electron/patches/node/support_v8_sandboxed_pointers.patch
electron-roller[bot] d02c9f8bc6
chore: bump chromium to 111.0.5544.3 (main) (#36820)
* chore: bump chromium in DEPS to 111.0.5522.0

* chore: bump chromium in DEPS to 111.0.5524.0

* chore: bump chromium in DEPS to 111.0.5526.0

* chore: bump chromium in DEPS to 111.0.5528.0

* chore: update patches/chromium/mas_avoid_usage_of_private_macos_apis.patch

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4132807

Fix simple code shear

* chore: update patches/chromium/unsandboxed_ppapi_processes_skip_zygote.patch

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4130675

Fix simple code shear

* chore: update patches/chromium/hack_plugin_response_interceptor_to_point_to_electron.patch

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4144281

Fix simple code shear; applied cleanly w/patch-fuzz

* chore: update patches/chromium/disable_unload_metrics.patch

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4126173

Fix simple code shear; applied cleanly w/patch-fuzz

* chore: update patches/chromium/feat_add_data_parameter_to_processsingleton.patch

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4144281

Fix simple code shear; applied cleanly w/patch-fuzz

* chore: update patches/chromium/preconnect_manager.patch

https://chromium-review.googlesource.com/c/chromium/src/+/4144281

Fix simple code shear; applied cleanly w/patch-fuzz

* chore: update patches/v8/force_cppheapcreateparams_to_be_noncopyable.patch

https://chromium-review.googlesource.com/c/v8/v8/+/3533019

Fix simple code shear; applied cleanly w/patch-fuzz

* chore: update patches

* chore: update patches/chromium/add_maximized_parameter_to_linuxui_getwindowframeprovider.patch

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4128765

Upstream added a new call to HeaderContext(), whose signature we have patched

* chore: bump chromium in DEPS to 111.0.5530.0

* chore: update patches

* Move ChildProcessHost* from content/common to content/browser

Xref: Move ChildProcessHost* from content/common to content/browser

* Remove RenderViewHostChanged

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4134103
[upstream removal of RenderViewHostChanged]

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4092763
Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4093234
Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4133892
Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4134103
[examples of upstream code adjusting to the change]

Upstream handles this change in roughly two approaches:

1. Move the code over to RenderFrameHostChanged(old_host, new_host)
   but test for new_host->IsInPrimaryMainFrame() before acting

2. Migrate to the PrimaryPageChanged(page) API and use
   page.GetMainDocument() to get the RenderFrameHost.

I've chosen 1. because electron_api_web_contents needed that pointer
to old_host to call RemoveInputEventListener(), but I may be missing
some context & would appreciate review on this commit.

* Make electron/shell/browser/relauncher_win.cc use <winternl.h>

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4129135

Many internal Windows types are now available in winternl.h
so upstrem no longer defines the types themselves.

* Move ChildProcessHost* from content/common to content/browser

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4134795

* fixup! Make electron/shell/browser/relauncher_win.cc use <winternl.h>

winternl.h does not define the field we need, so clone the struct Chromium was using into unnamed namespace

* fixup! Move ChildProcessHost* from content/common to content/browser

chore: update #includes too

* chore: bump chromium in DEPS to 111.0.5532.0

* chore: sync patches/chromium/pepper_plugin_support.patch

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4133323

manually reync patch; no code changes

* chore: sync patches/chromium/mas_no_private_api.patch

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4143865

the content/common/pseudonymization_salt.cc patch is no longer needed

* chore: sync patches/chromium/mas_disable_remote_accessibility.patch

patch-fuzz update; no manual changes

* chore: sync patches/chromium/build_do_not_depend_on_packed_resource_integrity.patch

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4111725

manually reync patch; no code changes

* chore: sync patches/chromium/create_browser_v8_snapshot_file_name_fuse.patch

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4133323

manually reync patch; no code changes

* chore: sync patches/v8/fix_build_deprecated_attribute_for_older_msvc_versions.patch

Xref: https://chromium-review.googlesource.com/c/v8/v8/+/4127230

patch-fuzz update; no manual changes

* chore: rebuild patches

* fixup! Remove RenderViewHostChanged

Use PrimaryPageChanged()

* chore: remove unused method TabsUpdateFunction::OnExecuteCodeFinished()

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4133991

This private, already-unused function showed up as a FTBFS because it
took a base::ListValue parameter and ListValue was removed upstream.

* task posting v3: remove includes of runner handles and IWYU task runners

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4133323

* chore: lint

* chore: more lint

* fixup! task posting v3: remove includes of runner handles and IWYU task runners

macOS, too

* fixup! task posting v3: remove includes of runner handles and IWYU task runners

* chore: bump chromium in DEPS to 111.0.5534.0

* chore: sync patches/chromium/allow_new_privileges_in_unsandboxed_child_processes.patch

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4141862

patch-fuzz update; no manual changes

* chore: sync patches/chromium/logging_win32_only_create_a_console_if_logging_to_stderr.patch

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4153110

Sync to minor upstream changes. Add const correctness.

* chore: sync electron/patches/chromium/feat_configure_launch_options_for_service_process.patch

https://chromium-review.googlesource.com/c/chromium/src/+/4141862

patch-fuzz update; no manual changes

* chore: patches/v8/fix_build_deprecated_attribute_for_older_msvc_versions.patch

sync https://chromium-review.googlesource.com/c/v8/v8/+/4147787

patch-fuzz update; no manual changes

* chore: update patches

* chore: bump chromium in DEPS to 111.0.5536.0

* chore: sync patches/chromium/allow_new_privileges_in_unsandboxed_child_processes.patch

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4141863

Sync with upstream code changes. Minor code golf for readability.

Note: upstream is laying groundwork for being able to work off of env vars
instead of switches. Doesn't affect us yet but worth being aware of.

> + // Environment variables could be supported in the future, but are not
> + // currently supported when launching with the zygote.

* chore: update patches/chromium/feat_expose_raw_response_headers_from_urlloader.patch

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4126836

patch-fuzz update; no manual changes

* chore: sync electron/patches/chromium/feat_configure_launch_options_for_service_process.patch

Xref: https://chromium-review.googlesource.com/c/chromium/src/+/4141863

manual sync

* chore: sync electron/patches/v8/fix_build_deprecated_attribute_for_older_msvc_versions.patch

https://chromium-review.googlesource.com/c/v8/v8/+/4147788

fuzz-patch

* chore: rebuild patches

* chore: bump chromium in DEPS to 111.0.5538.0

* chore: bump chromium in DEPS to 111.0.5540.0

* chore: update patches

* Remove sdk_forward_declarations

https://chromium-review.googlesource.com/c/chromium/src/+/4166680

* task posting v3: Remove task runner handles from codebase entirely

Refs https://chromium-review.googlesource.com/c/chromium/src/+/4150928

* Cleanup child_process_launcher_helper*

Refs https://chromium-review.googlesource.com/c/chromium/src/+/4141863

* fix: utilityprocess spec on macOS

* fix: build on windows

Refs https://chromium-review.googlesource.com/c/chromium/src/+/4141863

* chore: fix lint

* chore: bump chromium 111.0.5544.3

* chore: gen filenames.libcxx.gni

* Add check for Executable+Writable handles in renderer processes.

Refs https://chromium-review.googlesource.com/c/chromium/src/+/3774416

* fixup! Add check for Executable+Writable handles in renderer processes.

* 4143761: [110] Disable SwiftShader for WebGL on M1 Macs.

https://chromium-review.googlesource.com/c/chromium/src/+/4143761
(cherry picked from commit 2f74db3c2139424c416f92d9169aeaa8a2f9c1ec)

* chore: bump chromium to 111.0.5555.0

* 56085: Remove hmac.h include from ssl.h.

https://boringssl-review.googlesource.com/c/boringssl/+/56085

* 4167020: Remove forwarding headers

https://chromium-review.googlesource.com/c/chromium/src/+/4167020

* chore: bump chromium to 111.0.5559.0

* 4181044: Restrict WebCursor usage to RenderWidgetHostViewAura

https://chromium-review.googlesource.com/c/chromium/src/+/4181044

* 4189437: views: rename ink_drop_host_view to ink_drop_host

https://chromium-review.googlesource.com/c/chromium/src/+/4189437

* chore: bump chromium to 111.0.5560.0

* 4167016: win7dep: remove non aeroglass code

https://chromium-review.googlesource.com/c/chromium/src/+/4167016

* fixup after rebase: Remove forwarding header

s https://chromium-review.googlesource.com/c/chromium/src/+/4167020

* 4125755: Reland "Reject getDisplayMedia calls without user activation"

https://chromium-review.googlesource.com/c/chromium/src/+/4125755

* test: add workaround

* chore: update patches

* fix: alter coreModuleRegExp to prevent arm crash

* Revert "fix: alter coreModuleRegExp to prevent arm crash"

This reverts commit 7e50630c98137831a711c5abdbc8809e60cf1d73.

* 4218354: Disable the use of preserve_most on arm64 Windows

https://chromium-review.googlesource.com/c/v8/v8/+/4218354

* chore: review changes

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: deepak1556 <hop2deep@gmail.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-02-03 12:43:42 +01:00

250 lines
10 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 2e6f4a5c4b894a7425db110b3aadbe734f137327..c0c422e969543dcd570dabfd8ff0755abe37face 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -86,6 +86,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_util.cc b/src/crypto/crypto_util.cc
index 1fe573cd7b6894743a0986e87802960ad09e2dd9..ff1346f65f3c280da9962df87eb0710a3077ed03 100644
--- a/src/crypto/crypto_util.cc
+++ b/src/crypto/crypto_util.cc
@@ -324,10 +324,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(),
@@ -339,10 +364,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));
}
@@ -671,6 +697,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);
@@ -692,6 +728,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 43247cf3d70b78a1e332d55336c2a5175a155e93..b9066b4b0fb9a529c4cbf774e5aacfd8a7aa99c8 100644
--- a/src/crypto/crypto_util.h
+++ b/src/crypto/crypto_util.h
@@ -280,7 +280,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/node_i18n.cc b/src/node_i18n.cc
index 808f1fa8d77718e0d44033203485fb2c2796d8e1..56ea735e74fe6d4296d3b179ccb9792daac568b5 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;
diff --git a/src/node_internals.h b/src/node_internals.h
index efbdbeabf5a6afb658cbdc7888f94952e55f4f71..8b37639361e8902d7e1481071d3ec24be30339e0 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -99,7 +99,9 @@ v8::Maybe<bool> 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;
@@ -118,7 +120,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 45a16d9de43703c2115dde85c9faae3a04be2a88..97917c91c06dc47dfa6be2c194944cdc93e6bd7f 100644
--- a/src/node_serdes.cc
+++ b/src/node_serdes.cc
@@ -29,6 +29,11 @@ using v8::ValueSerializer;
namespace serdes {
+v8::ArrayBuffer::Allocator* GetAllocator() {
+ static v8::ArrayBuffer::Allocator* allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
+ return allocator;
+};
+
class SerializerContext : public BaseObject,
public ValueSerializer::Delegate {
public:
@@ -37,10 +42,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 +71,7 @@ class SerializerContext : public BaseObject,
private:
ValueSerializer serializer_;
+ size_t last_length_ = 0;
};
class DeserializerContext : public BaseObject,
@@ -144,6 +155,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 = GetAllocator()->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 +238,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/test/parallel/test-v8-serialize-leak.js b/test/parallel/test-v8-serialize-leak.js
index a90c398adcdaf30491a0fecdcf00895038d62e69..f5b8a1430ad2033eae06ca0157af2fb51d3f36a5 100644
--- a/test/parallel/test-v8-serialize-leak.js
+++ b/test/parallel/test-v8-serialize-leak.js
@@ -23,5 +23,5 @@ const after = process.memoryUsage.rss();
if (process.config.variables.asan) {
assert(after < before * 10, `asan: before=${before} after=${after}`);
} else {
- assert(after < before * 2, `before=${before} after=${after}`);
+ assert(after < before * 3, `before=${before} after=${after}`);
}