mirror of
https://github.com/electron/electron.git
synced 2026-05-02 03:00:22 -04:00
fix: constrain AllowUniversalAccessFromFileURLs to file: origins in agent cluster key assignment (#50789)
* fix: constrain AllowUniversalAccessFromFileURLs to file: origins in agent cluster key assignment Fixes #50242 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * sync patch with upstream CL * add test --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -152,3 +152,4 @@ chore_register_node_as_a_dynamic_trace_category_prefix.patch
|
||||
fix_make_macos_text_replacement_work_on_contenteditable.patch
|
||||
fix_allow_reentrancy_on_downloadmanagerimpl_observer_list.patch
|
||||
build_gn_arg_to_support_linker_wrapper_script_on_windows.patch
|
||||
fix_constrain_allowuniversalaccessfromfileurls_to_file_origins_in.patch
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Calvin Watford <cwatford@makenotion.com>
|
||||
Date: Sun, 12 Apr 2026 21:24:57 -0700
|
||||
Subject: fix: constrain AllowUniversalAccessFromFileURLs to file: origins in
|
||||
agent assignment
|
||||
|
||||
HasPotentialUniversalAccessPrivilege() was treating the
|
||||
AllowUniversalAccessFromFileURLs setting as unconditional, returning
|
||||
true for all origins regardless of scheme. This caused non-file origins
|
||||
(http://, https://, and custom schemes) to lose their browser-provided
|
||||
AgentClusterKey when the setting was enabled, overriding it with a
|
||||
universal file agent key and routing them to universal_access_agent_
|
||||
which carries no key.
|
||||
|
||||
Electron enables AllowUniversalAccessFromFileURLs in all renderers via
|
||||
the grant_file_protocol_extra_privileges fuse (on by default). After
|
||||
https://crrev.com/c/7079680 moved cross-origin isolation status to the
|
||||
renderer's per-context agent cluster key, this caused
|
||||
self.crossOriginIsolated to return false even with COOP + COEP headers
|
||||
correctly set on non-file origins.
|
||||
|
||||
The fix splits the single has_potential_universal_access_privilege
|
||||
boolean in WindowAgentFactory::GetAgentForAgentClusterKey() into two
|
||||
separate parameters:
|
||||
|
||||
- web_security_disabled: applies to all origins when web security is
|
||||
off (--disable-web-security, --run-web-tests).
|
||||
- allow_universal_access_from_file_urls: only takes effect for file:
|
||||
scheme origins (those with IsUniversalFileAgent() agent cluster
|
||||
keys), preserving their existing routing to universal_access_agent_.
|
||||
|
||||
This aligns the agent assignment logic with the origin privilege
|
||||
granting code in the same file (DocumentLoader::CalculateOrigin), which
|
||||
already correctly gates AllowUniversalAccessFromFileURLs behind
|
||||
origin->IsLocal().
|
||||
|
||||
This patch should be upstreamed, with updates to surrounding doc
|
||||
comments + tests.
|
||||
|
||||
Upstream CL: https://chromium-review.googlesource.com/c/chromium/src/+/7795303
|
||||
Chromium bug: https://crbug.com/505299810
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/execution_context/window_agent_factory.cc b/third_party/blink/renderer/core/execution_context/window_agent_factory.cc
|
||||
index 86ce2d493dc833dd1601787fc042b8a4a612fc2e..b9bd1f459f240401d7a6b0bce03cf82b6b54e9fc 100644
|
||||
--- a/third_party/blink/renderer/core/execution_context/window_agent_factory.cc
|
||||
+++ b/third_party/blink/renderer/core/execution_context/window_agent_factory.cc
|
||||
@@ -20,19 +20,27 @@ WindowAgentFactory::WindowAgentFactory(
|
||||
AgentGroupScheduler& agent_group_scheduler)
|
||||
: agent_group_scheduler_(agent_group_scheduler) {}
|
||||
|
||||
+WindowAgent* WindowAgentFactory::GetOrCreateUniversalAccessAgent() {
|
||||
+ if (!universal_access_agent_) {
|
||||
+ universal_access_agent_ =
|
||||
+ MakeGarbageCollected<WindowAgent>(*agent_group_scheduler_);
|
||||
+ }
|
||||
+ return universal_access_agent_.Get();
|
||||
+}
|
||||
+
|
||||
WindowAgent* WindowAgentFactory::GetAgentForAgentClusterKey(
|
||||
- bool has_potential_universal_access_privilege,
|
||||
+ bool is_web_security_disabled,
|
||||
+ bool allow_universal_access_from_file_urls,
|
||||
const AgentClusterKey& agent_cluster_key) {
|
||||
- if (has_potential_universal_access_privilege) {
|
||||
- if (!universal_access_agent_) {
|
||||
- universal_access_agent_ =
|
||||
- MakeGarbageCollected<WindowAgent>(*agent_group_scheduler_);
|
||||
- }
|
||||
- return universal_access_agent_.Get();
|
||||
+ if (is_web_security_disabled) {
|
||||
+ return GetOrCreateUniversalAccessAgent();
|
||||
}
|
||||
|
||||
// For `file:` scheme origins.
|
||||
if (agent_cluster_key.IsUniversalFileAgent()) {
|
||||
+ if (allow_universal_access_from_file_urls) {
|
||||
+ return GetOrCreateUniversalAccessAgent();
|
||||
+ }
|
||||
if (!file_url_agent_) {
|
||||
file_url_agent_ = MakeGarbageCollected<WindowAgent>(
|
||||
*agent_group_scheduler_, agent_cluster_key);
|
||||
diff --git a/third_party/blink/renderer/core/execution_context/window_agent_factory.h b/third_party/blink/renderer/core/execution_context/window_agent_factory.h
|
||||
index b5464975a3c365a29e342b0dd57a8a73a311924a..72ebd275330e61a8abebfe6d2c06f42544a83bec 100644
|
||||
--- a/third_party/blink/renderer/core/execution_context/window_agent_factory.h
|
||||
+++ b/third_party/blink/renderer/core/execution_context/window_agent_factory.h
|
||||
@@ -40,12 +40,15 @@ class WindowAgentFactory final : public GarbageCollected<WindowAgentFactory> {
|
||||
// * --run-web-tests is set,
|
||||
// * or, the Blink instance is running for Android WebView.
|
||||
WindowAgent* GetAgentForAgentClusterKey(
|
||||
- bool has_potential_universal_access_privilege,
|
||||
+ bool is_web_security_disabled,
|
||||
+ bool allow_universal_access_from_file_urls,
|
||||
const AgentClusterKey& agent_cluster_key);
|
||||
|
||||
void Trace(Visitor*) const;
|
||||
|
||||
private:
|
||||
+ WindowAgent* GetOrCreateUniversalAccessAgent();
|
||||
+
|
||||
// Use a shared instance of Agent for all frames if a frame may have the
|
||||
// universal access privilege.
|
||||
WeakMember<WindowAgent> universal_access_agent_;
|
||||
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
|
||||
index 2344e1d62f4a2d7fdf139b64b6c71ede1e3094ce..f79f870408a71e107933219f30ea6dc3afaa8716 100644
|
||||
--- a/third_party/blink/renderer/core/loader/document_loader.cc
|
||||
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
|
||||
@@ -2600,22 +2600,16 @@ bool ShouldReuseDOMWindow(LocalDOMWindow* window,
|
||||
return *window_coi_key == *navigation_coi_key;
|
||||
}
|
||||
|
||||
-namespace {
|
||||
-
|
||||
-bool HasPotentialUniversalAccessPrivilege(LocalFrame* frame) {
|
||||
- return !frame->GetSettings()->GetWebSecurityEnabled() ||
|
||||
- frame->GetSettings()->GetAllowUniversalAccessFromFileURLs();
|
||||
-}
|
||||
-
|
||||
-} // namespace
|
||||
-
|
||||
WindowAgent* GetWindowAgentForAgentClusterKey(
|
||||
LocalFrame* frame,
|
||||
const AgentClusterKey& agent_cluster_key) {
|
||||
// TODO(keishi): Also check if AllowUniversalAccessFromFileURLs might
|
||||
// dynamically change.
|
||||
+ Settings* settings = frame->GetSettings();
|
||||
return frame->window_agent_factory().GetAgentForAgentClusterKey(
|
||||
- HasPotentialUniversalAccessPrivilege(frame), agent_cluster_key);
|
||||
+ /*is_web_security_disabled=*/!settings->GetWebSecurityEnabled(),
|
||||
+ /*allow_universal_access_from_file_urls=*/
|
||||
+ settings->GetAllowUniversalAccessFromFileURLs(), agent_cluster_key);
|
||||
}
|
||||
|
||||
// Inheriting cases use their agent's AgentClusterKey value, which is set
|
||||
@@ -2716,7 +2710,7 @@ void DocumentLoader::InitializeWindow(Document* owner_document) {
|
||||
// WindowAgentFactory::GetAgentForOrigin(), as the two conditions below hand
|
||||
// out universal WindowAgent objects, and thus override the AgentClusterKey
|
||||
// provided by the browser process.
|
||||
- } else if (HasPotentialUniversalAccessPrivilege(frame_.Get()) ||
|
||||
+ } else if (!frame_->GetSettings()->GetWebSecurityEnabled() ||
|
||||
security_origin->IsLocal()) {
|
||||
// In this case we either have AllowUniversalAccessFromFileURLs enabled, or
|
||||
// WebSecurity is disabled, or it's a local scheme such as file://; any of
|
||||
@@ -263,6 +263,35 @@ describe('focus handling', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('cross origin isolation', () => {
|
||||
afterEach(closeAllWindows);
|
||||
|
||||
let server: http.Server;
|
||||
let serverUrl: string;
|
||||
|
||||
before(async () => {
|
||||
server = http.createServer((_req, res) => {
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
|
||||
res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
|
||||
res.end('<!doctype html>');
|
||||
});
|
||||
serverUrl = (await listen(server)).url;
|
||||
});
|
||||
|
||||
after(() => {
|
||||
server.close();
|
||||
});
|
||||
|
||||
it('is enabled by COOP and COEP headers', async () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
await w.loadURL(serverUrl);
|
||||
|
||||
const crossOriginIsolated = await w.webContents.executeJavaScript('globalThis.crossOriginIsolated');
|
||||
expect(crossOriginIsolated).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('web security', () => {
|
||||
afterEach(closeAllWindows);
|
||||
let server: http.Server;
|
||||
|
||||
Reference in New Issue
Block a user