fix: make child windows not crash when ipc messages are received (#19553)

This commit is contained in:
Samuel Attard 2019-08-05 12:50:51 -07:00 committed by Jeremy Apthorp
parent cfd230d7f1
commit 33a9d898a6
6 changed files with 39 additions and 12 deletions

View file

@ -34,7 +34,7 @@ const mergeOptions = function (child, parent, visited) {
if (key in child && key !== 'webPreferences') continue if (key in child && key !== 'webPreferences') continue
const value = parent[key] const value = parent[key]
if (typeof value === 'object') { if (typeof value === 'object' && !Array.isArray(value)) {
child[key] = mergeOptions(child[key] || {}, value, visited) child[key] = mergeOptions(child[key] || {}, value, visited)
} else { } else {
child[key] = value child[key] = value

View file

@ -234,6 +234,7 @@ const char kNativeWindowOpen[] = "native-window-open";
const char kWebviewTag[] = "webview-tag"; const char kWebviewTag[] = "webview-tag";
const char kDisableElectronSiteInstanceOverrides[] = const char kDisableElectronSiteInstanceOverrides[] =
"disable-electron-site-instance-overrides"; "disable-electron-site-instance-overrides";
const char kEnableNodeLeakageInRenderers[] = "enable-node-leakage-in-renderers";
// Command switch passed to renderer process to control nodeIntegration. // Command switch passed to renderer process to control nodeIntegration.
const char kNodeIntegrationInWorker[] = "node-integration-in-worker"; const char kNodeIntegrationInWorker[] = "node-integration-in-worker";

View file

@ -118,6 +118,7 @@ extern const char kNodeIntegrationInWorker[];
extern const char kWebviewTag[]; extern const char kWebviewTag[];
extern const char kNodeIntegrationInSubFrames[]; extern const char kNodeIntegrationInSubFrames[];
extern const char kDisableElectronSiteInstanceOverrides[]; extern const char kDisableElectronSiteInstanceOverrides[];
extern const char kEnableNodeLeakageInRenderers[];
extern const char kWidevineCdmPath[]; extern const char kWidevineCdmPath[];
extern const char kWidevineCdmVersion[]; extern const char kWidevineCdmVersion[];

View file

@ -69,16 +69,25 @@ void AtomRenderFrameObserver::DidCreateScriptContext(
if (ShouldNotifyClient(world_id)) if (ShouldNotifyClient(world_id))
renderer_client_->DidCreateScriptContext(context, render_frame_); renderer_client_->DidCreateScriptContext(context, render_frame_);
auto* command_line = base::CommandLine::ForCurrentProcess();
bool use_context_isolation = renderer_client_->isolated_world(); bool use_context_isolation = renderer_client_->isolated_world();
// This logic matches the EXPLAINED logic in atom_renderer_client.cc
// to avoid explaining it twice go check that implementation in
// DidCreateScriptContext();
bool is_main_world = IsMainWorld(world_id); bool is_main_world = IsMainWorld(world_id);
bool is_main_frame = render_frame_->IsMainFrame(); bool is_main_frame = render_frame_->IsMainFrame();
bool is_not_opened = !render_frame_->GetWebFrame()->Opener(); bool reuse_renderer_processes_enabled =
command_line->HasSwitch(switches::kDisableElectronSiteInstanceOverrides);
bool is_not_opened =
!render_frame_->GetWebFrame()->Opener() ||
command_line->HasSwitch(switches::kEnableNodeLeakageInRenderers);
bool allow_node_in_sub_frames = bool allow_node_in_sub_frames =
base::CommandLine::ForCurrentProcess()->HasSwitch( command_line->HasSwitch(switches::kNodeIntegrationInSubFrames);
switches::kNodeIntegrationInSubFrames);
bool should_create_isolated_context = bool should_create_isolated_context =
use_context_isolation && is_main_world && use_context_isolation && is_main_world &&
(is_main_frame || allow_node_in_sub_frames) && is_not_opened; (is_main_frame || allow_node_in_sub_frames) &&
(is_not_opened || reuse_renderer_processes_enabled);
if (should_create_isolated_context) { if (should_create_isolated_context) {
CreateIsolatedWorldContext(); CreateIsolatedWorldContext();

View file

@ -77,14 +77,26 @@ void AtomRendererClient::DidCreateScriptContext(
// TODO(zcbenz): Do not create Node environment if node integration is not // TODO(zcbenz): Do not create Node environment if node integration is not
// enabled. // enabled.
// Do not load node if we're aren't a main frame or a devtools extension auto* command_line = base::CommandLine::ForCurrentProcess();
// Only load node if we are a main frame or a devtools extension
// unless node support has been explicitly enabled for sub frames // unless node support has been explicitly enabled for sub frames
bool is_main_frame = bool reuse_renderer_processes_enabled =
render_frame->IsMainFrame() && !render_frame->GetWebFrame()->Opener(); command_line->HasSwitch(switches::kDisableElectronSiteInstanceOverrides);
// Consider the window not "opened" if it does not have an Opener, or if a
// user has manually opted in to leaking node in the renderer
bool is_not_opened =
!render_frame->GetWebFrame()->Opener() ||
command_line->HasSwitch(switches::kEnableNodeLeakageInRenderers);
// Consider this the main frame if it is both a Main Frame and it wasn't
// opened. We allow an opened main frame to have node if renderer process
// reuse is enabled as that will correctly free node environments prevent a
// leak in child windows.
bool is_main_frame = render_frame->IsMainFrame() &&
(is_not_opened || reuse_renderer_processes_enabled);
bool is_devtools = IsDevToolsExtension(render_frame); bool is_devtools = IsDevToolsExtension(render_frame);
bool allow_node_in_subframes = bool allow_node_in_subframes =
base::CommandLine::ForCurrentProcess()->HasSwitch( command_line->HasSwitch(switches::kNodeIntegrationInSubFrames);
switches::kNodeIntegrationInSubFrames);
bool should_load_node = bool should_load_node =
(is_main_frame || is_devtools || allow_node_in_subframes) && (is_main_frame || is_devtools || allow_node_in_subframes) &&
!IsWebViewFrame(renderer_context, render_frame); !IsWebViewFrame(renderer_context, render_frame);
@ -112,7 +124,6 @@ void AtomRendererClient::DidCreateScriptContext(
DCHECK(!context.IsEmpty()); DCHECK(!context.IsEmpty());
node::Environment* env = node::Environment* env =
node_bindings_->CreateEnvironment(context, nullptr, true); node_bindings_->CreateEnvironment(context, nullptr, true);
auto* command_line = base::CommandLine::ForCurrentProcess();
// If we have disabled the site instance overrides we should prevent loading // If we have disabled the site instance overrides we should prevent loading
// any non-context aware native module // any non-context aware native module
if (command_line->HasSwitch(switches::kDisableElectronSiteInstanceOverrides)) if (command_line->HasSwitch(switches::kDisableElectronSiteInstanceOverrides))

View file

@ -39,7 +39,10 @@ v8::Local<v8::Object> GetIpcObject(v8::Local<v8::Context> context) {
auto global_object = context->Global(); auto global_object = context->Global();
auto value = auto value =
global_object->GetPrivate(context, private_binding_key).ToLocalChecked(); global_object->GetPrivate(context, private_binding_key).ToLocalChecked();
DCHECK(!value.IsEmpty() && value->IsObject()); if (value.IsEmpty() || !value->IsObject()) {
LOG(ERROR) << "Attempted to get the 'ipcNative' object but it was missing";
return v8::Local<v8::Object>();
}
return value->ToObject(context).ToLocalChecked(); return value->ToObject(context).ToLocalChecked();
} }
@ -50,6 +53,8 @@ void InvokeIpcCallback(v8::Local<v8::Context> context,
auto* isolate = context->GetIsolate(); auto* isolate = context->GetIsolate();
auto ipcNative = GetIpcObject(context); auto ipcNative = GetIpcObject(context);
if (ipcNative.IsEmpty())
return;
// Only set up the node::CallbackScope if there's a node environment. // Only set up the node::CallbackScope if there's a node environment.
// Sandboxed renderers don't have a node environment. // Sandboxed renderers don't have a node environment.