From c0e20dd0b0283f337cb29cd42ae951c7a4a80160 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Tue, 24 May 2022 13:56:22 +0000 Subject: [PATCH] Bug 1770468 - Report-only wasm-unsafe-eval in MV2 r=mixedpuppy,freddyb,ckerschb For backcompat, do not enforce wasm-unsafe-eval even if the extension has specified a custom CSP. Do report the errors though, to allow extension authors to discover the issue and fix it. Differential Revision: https://phabricator.services.mozilla.com/D147105 --- caps/nsScriptSecurityManager.cpp | 11 ++++++ .../extensions/test/xpcshell/test_ext_wasm.js | 35 +++++++++++++++++-- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index b81d02041172..ff64eb80f726 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -515,6 +515,17 @@ bool nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction( if (NS_FAILED(csp->GetAllowsWasmEval(&reportViolation, &evalOK))) { return false; } + if (!evalOK) { + // Historically, CSP did not block WebAssembly in Firefox, and some + // add-ons use wasm and a stricter CSP. To avoid breaking them, ignore + // 'wasm-unsafe-eval' violations for MV2 extensions. + // TODO bug 1770909: remove this exception. + auto* addonPolicy = BasePrincipal::Cast(subjectPrincipal)->AddonPolicy(); + if (addonPolicy && addonPolicy->ManifestVersion() == 2) { + reportViolation = true; + evalOK = true; + } + } } if (reportViolation) { diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_wasm.js b/toolkit/components/extensions/test/xpcshell/test_ext_wasm.js index 8b76a6dfd090..d481c5f06ac8 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_wasm.js +++ b/toolkit/components/extensions/test/xpcshell/test_ext_wasm.js @@ -8,6 +8,12 @@ Services.prefs.setBoolPref("extensions.manifestV3.enabled", true); function background() { globalThis.onsecuritypolicyviolation = event => { browser.test.assertEq("wasm-eval", event.blockedURI, "blockedURI"); + if (browser.runtime.getManifest().version === 2) { + // In MV2, wasm eval violations are advisory only, as a transition tool. + browser.test.assertEq(event.disposition, "report", "MV2 disposition"); + } else { + browser.test.assertEq(event.disposition, "enforce", "MV3 disposition"); + } browser.test.sendMessage("violated_csp", event.originalPolicy); }; try { @@ -53,7 +59,8 @@ add_task(async function test_wasm_v2_explicit() { await extension.unload(); }); -add_task(async function test_wasm_v2_blocked() { +// MV3 counterpart is test_wasm_v3_blocked_by_custom_csp. +add_task(async function test_wasm_v2_blocked_in_report_only_mode() { let extension = ExtensionTestUtils.loadExtension({ background, manifest: { @@ -63,7 +70,8 @@ add_task(async function test_wasm_v2_blocked() { }); await extension.startup(); - equal(await extension.awaitMessage("result"), "blocked"); + // "allowed" because wasm-unsafe-eval in MV2 is in report-only mode. + equal(await extension.awaitMessage("result"), "allowed"); equal( await extension.awaitMessage("violated_csp"), "object-src 'none'; script-src 'self'" @@ -71,7 +79,7 @@ add_task(async function test_wasm_v2_blocked() { await extension.unload(); }); -add_task(async function test_wasm_v3() { +add_task(async function test_wasm_v3_blocked_by_default() { let extension = ExtensionTestUtils.loadExtension({ background, manifest: { @@ -88,6 +96,27 @@ add_task(async function test_wasm_v3() { await extension.unload(); }); +// MV2 counterpart is test_wasm_v2_blocked_in_report_only_mode. +add_task(async function test_wasm_v3_blocked_by_custom_csp() { + let extension = ExtensionTestUtils.loadExtension({ + background, + manifest: { + manifest_version: 3, + content_security_policy: { + extension_pages: "object-src; script-src 'self'", + }, + }, + }); + + await extension.startup(); + equal(await extension.awaitMessage("result"), "blocked"); + equal( + await extension.awaitMessage("violated_csp"), + "object-src 'none'; script-src 'self'" + ); + await extension.unload(); +}); + add_task(async function test_wasm_v3_allowed() { let extension = ExtensionTestUtils.loadExtension({ background,