From 54d9c30a346d86e71c7564b84bff710fb8c49807 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Tue, 23 Apr 2024 06:30:02 +0200 Subject: Merging upstream version 125.0.2. Signed-off-by: Daniel Baumann --- dom/canvas/CanvasRenderingContext2D.cpp | 29 ++- dom/canvas/CanvasRenderingContext2D.h | 22 +- .../en-US/chrome/security/security.properties | 2 +- dom/security/nsContentSecurityUtils.cpp | 48 ++-- dom/security/test/general/browser.toml | 10 - .../test/general/browser_test_http_download.js | 275 --------------------- dom/security/test/general/http_download_page.html | 23 -- dom/security/test/general/http_download_server.sjs | 20 -- dom/security/test/https-only/browser_save_as.js | 10 +- .../browser_test_mixed_content_download.js | 2 +- dom/serviceworkers/test/browser_download.js | 2 +- 11 files changed, 74 insertions(+), 369 deletions(-) delete mode 100644 dom/security/test/general/browser_test_http_download.js delete mode 100644 dom/security/test/general/http_download_page.html delete mode 100644 dom/security/test/general/http_download_server.sjs (limited to 'dom') diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 529466cc81..62f6e6443d 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -3463,7 +3463,9 @@ void CanvasRenderingContext2D::ArcTo(double aX1, double aY1, double aX2, return aError.ThrowIndexSizeError("Negative radius"); } - EnsureWritablePath(); + if (!EnsureWritablePath()) { + return; + } // Current point in user space! Point p0 = mPathBuilder->CurrentPoint(); @@ -3535,7 +3537,9 @@ void CanvasRenderingContext2D::Arc(double aX, double aY, double aR, return; } - EnsureWritablePath(); + if (!EnsureWritablePath()) { + return; + } EnsureActivePath(); @@ -3545,7 +3549,9 @@ void CanvasRenderingContext2D::Arc(double aX, double aY, double aR, void CanvasRenderingContext2D::Rect(double aX, double aY, double aW, double aH) { - EnsureWritablePath(); + if (!EnsureWritablePath()) { + return; + } if (!std::isfinite(aX) || !std::isfinite(aY) || !std::isfinite(aW) || !std::isfinite(aH)) { @@ -3741,7 +3747,9 @@ void CanvasRenderingContext2D::RoundRect( const UnrestrictedDoubleOrDOMPointInitOrUnrestrictedDoubleOrDOMPointInitSequence& aRadii, ErrorResult& aError) { - EnsureWritablePath(); + if (!EnsureWritablePath()) { + return; + } PathBuilder* builder = mPathBuilder; Maybe transform = Nothing(); @@ -3759,7 +3767,9 @@ void CanvasRenderingContext2D::Ellipse(double aX, double aY, double aRadiusX, return aError.ThrowIndexSizeError("Negative radius"); } - EnsureWritablePath(); + if (!EnsureWritablePath()) { + return; + } ArcToBezier(this, Point(aX, aY), Size(aRadiusX, aRadiusY), aStartAngle, aEndAngle, aAnticlockwise, aRotation); @@ -3780,10 +3790,14 @@ void CanvasRenderingContext2D::FlushPathTransform() { mPathTransformDirty = false; } -void CanvasRenderingContext2D::EnsureWritablePath() { +bool CanvasRenderingContext2D::EnsureWritablePath() { EnsureTarget(); + // NOTE: IsTargetValid() may be false here (mTarget == sErrorTarget) but we // go ahead and create a path anyway since callers depend on that. + if (NS_WARN_IF(!mTarget)) { + return false; + } FillRule fillRule = CurrentState().fillRule; @@ -3792,7 +3806,7 @@ void CanvasRenderingContext2D::EnsureWritablePath() { } if (mPathBuilder) { - return; + return true; } if (!mPath) { @@ -3800,6 +3814,7 @@ void CanvasRenderingContext2D::EnsureWritablePath() { } else { mPathBuilder = mPath->CopyToBuilder(fillRule); } + return true; } void CanvasRenderingContext2D::EnsureUserSpacePath( diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h index 75a57ab14f..bfcbfccec2 100644 --- a/dom/canvas/CanvasRenderingContext2D.h +++ b/dom/canvas/CanvasRenderingContext2D.h @@ -364,14 +364,18 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal, } void ClosePath() { - EnsureWritablePath(); + if (!EnsureWritablePath()) { + return; + } mPathBuilder->Close(); mPathPruned = false; } void MoveTo(double aX, double aY) { - EnsureWritablePath(); + if (!EnsureWritablePath()) { + return; + } mozilla::gfx::Point pos(ToFloat(aX), ToFloat(aY)); if (!pos.IsFinite()) { @@ -383,13 +387,17 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal, } void LineTo(double aX, double aY) { - EnsureWritablePath(); + if (!EnsureWritablePath()) { + return; + } LineTo(mozilla::gfx::Point(ToFloat(aX), ToFloat(aY))); } void QuadraticCurveTo(double aCpx, double aCpy, double aX, double aY) { - EnsureWritablePath(); + if (!EnsureWritablePath()) { + return; + } mozilla::gfx::Point cp1(ToFloat(aCpx), ToFloat(aCpy)); mozilla::gfx::Point cp2(ToFloat(aX), ToFloat(aY)); @@ -408,7 +416,9 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal, void BezierCurveTo(double aCp1x, double aCp1y, double aCp2x, double aCp2y, double aX, double aY) { - EnsureWritablePath(); + if (!EnsureWritablePath()) { + return; + } BezierTo(mozilla::gfx::Point(ToFloat(aCp1x), ToFloat(aCp1y)), mozilla::gfx::Point(ToFloat(aCp2x), ToFloat(aCp2y)), @@ -680,7 +690,7 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal, /* This function ensures there is a writable pathbuilder available */ - void EnsureWritablePath(); + bool EnsureWritablePath(); // Ensures a path in UserSpace is available. void EnsureUserSpacePath( diff --git a/dom/locales/en-US/chrome/security/security.properties b/dom/locales/en-US/chrome/security/security.properties index fc58fe4f7d..c19fc2d2bf 100644 --- a/dom/locales/en-US/chrome/security/security.properties +++ b/dom/locales/en-US/chrome/security/security.properties @@ -44,7 +44,7 @@ LoadingMixedActiveContent2=Loading mixed (insecure) active content “%1$S” on LoadingMixedDisplayContent2=Loading mixed (insecure) display content “%1$S” on a secure page LoadingMixedDisplayObjectSubrequestDeprecation=Loading mixed (insecure) content “%1$S” within a plugin on a secure page is discouraged and will be blocked soon. # LOCALIZATION NOTE: "%S" is the URI of the insecure mixed content download -BlockedInsecureDownload = We blocked a download that’s not secure: “%S”. +MixedContentBlockedDownload = Blocked downloading insecure content “%S”. # LOCALIZATION NOTE: Do not translate "allow-scripts", "allow-same-origin", "sandbox" or "iframe" BothAllowScriptsAndSameOriginPresent=An iframe which has both allow-scripts and allow-same-origin for its sandbox attribute can remove its sandboxing. diff --git a/dom/security/nsContentSecurityUtils.cpp b/dom/security/nsContentSecurityUtils.cpp index 01e9c6d5db..d2c1b257bc 100644 --- a/dom/security/nsContentSecurityUtils.cpp +++ b/dom/security/nsContentSecurityUtils.cpp @@ -1670,25 +1670,37 @@ long nsContentSecurityUtils::ClassifyDownload( nsCOMPtr contentLocation; aChannel->GetURI(getter_AddRefs(contentLocation)); - if (StaticPrefs::dom_block_download_insecure()) { - // If we are not dealing with a potentially trustworthy origin, or a URI - // that is safe to be loaded like e.g. data:, then we block the load. - bool isInsecureDownload = - !nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin( - contentLocation) && - !nsMixedContentBlocker::URISafeToBeLoadedInSecureContext( - contentLocation); - - Telemetry::Accumulate(mozilla::Telemetry::INSECURE_DOWNLOADS, - isInsecureDownload); - - if (isInsecureDownload) { - nsCOMPtr httpChannel = do_QueryInterface(aChannel); - if (httpChannel) { - LogMessageToConsole(httpChannel, "BlockedInsecureDownload"); - } - return nsITransfer::DOWNLOAD_POTENTIALLY_UNSAFE; + nsCOMPtr loadingPrincipal = loadInfo->GetLoadingPrincipal(); + if (!loadingPrincipal) { + loadingPrincipal = loadInfo->TriggeringPrincipal(); + } + // Creating a fake Loadinfo that is just used for the MCB check. + nsCOMPtr secCheckLoadInfo = new mozilla::net::LoadInfo( + loadingPrincipal, loadInfo->TriggeringPrincipal(), nullptr, + nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK, + nsIContentPolicy::TYPE_FETCH); + // Disable HTTPS-Only checks for that loadinfo. This is required because + // otherwise nsMixedContentBlocker::ShouldLoad would assume that the request + // is safe, because HTTPS-Only is handling it. + secCheckLoadInfo->SetHttpsOnlyStatus(nsILoadInfo::HTTPS_ONLY_EXEMPT); + + int16_t decission = nsIContentPolicy::ACCEPT; + nsMixedContentBlocker::ShouldLoad(false, // aHadInsecureImageRedirect + contentLocation, // aContentLocation, + secCheckLoadInfo, // aLoadinfo + false, // aReportError + &decission // aDecision + ); + Telemetry::Accumulate(mozilla::Telemetry::MIXED_CONTENT_DOWNLOADS, + decission != nsIContentPolicy::ACCEPT); + + if (StaticPrefs::dom_block_download_insecure() && + decission != nsIContentPolicy::ACCEPT) { + nsCOMPtr httpChannel = do_QueryInterface(aChannel); + if (httpChannel) { + LogMessageToConsole(httpChannel, "MixedContentBlockedDownload"); } + return nsITransfer::DOWNLOAD_POTENTIALLY_UNSAFE; } if (loadInfo->TriggeringPrincipal()->IsSystemPrincipal()) { diff --git a/dom/security/test/general/browser.toml b/dom/security/test/general/browser.toml index c6d6b4bf79..0f4ec5b224 100644 --- a/dom/security/test/general/browser.toml +++ b/dom/security/test/general/browser.toml @@ -48,16 +48,6 @@ support-files = [ "file_gpc_server.sjs", ] -["browser_test_http_download.js"] -skip-if = [ - "win11_2009", # Bug 1784764 - "os == 'linux' && !debug", -] -support-files = [ - "http_download_page.html", - "http_download_server.sjs" -] - ["browser_test_referrer_loadInOtherProcess.js"] ["browser_test_report_blocking.js"] diff --git a/dom/security/test/general/browser_test_http_download.js b/dom/security/test/general/browser_test_http_download.js deleted file mode 100644 index 35e3fdfc4b..0000000000 --- a/dom/security/test/general/browser_test_http_download.js +++ /dev/null @@ -1,275 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * https://creativecommons.org/publicdomain/zero/1.0/ */ - -ChromeUtils.defineESModuleGetters(this, { - Downloads: "resource://gre/modules/Downloads.sys.mjs", - DownloadsCommon: "resource:///modules/DownloadsCommon.sys.mjs", -}); - -const HandlerService = Cc[ - "@mozilla.org/uriloader/handler-service;1" -].getService(Ci.nsIHandlerService); - -const MIMEService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); - -// Using insecure HTTP URL for a test cases around HTTP downloads -let INSECURE_BASE_URL = - getRootDirectory(gTestPath).replace( - "chrome://mochitests/content/", - // eslint-disable-next-line @microsoft/sdl/no-insecure-url - "http://example.com/" - ) + "http_download_page.html"; - -function promiseFocus() { - return new Promise(resolve => { - waitForFocus(resolve); - }); -} - -async function task_openPanel() { - await promiseFocus(); - - let promise = BrowserTestUtils.waitForPopupEvent( - DownloadsPanel.panel, - "shown" - ); - DownloadsPanel.showPanel(); - await promise; -} - -const downloadMonitoringView = { - _listeners: [], - onDownloadAdded(download) { - for (let listener of this._listeners) { - listener(download); - } - this._listeners = []; - }, - waitForDownload(listener) { - this._listeners.push(listener); - }, -}; - -/** - * Waits until a download is triggered. - * Unless the always_ask_before_handling_new_types pref is true, the download - * will simply be saved, so resolve when the view is notified of the new - * download. Otherwise, it waits until a prompt is shown, selects the choosen - * , then accepts the dialog - * @param [action] Which action to select, either: - * "handleInternally", "save" or "open". - * @returns {Promise} Resolved once done. - */ - -function shouldTriggerDownload(action = "save") { - if ( - Services.prefs.getBoolPref( - "browser.download.always_ask_before_handling_new_types" - ) - ) { - return new Promise((resolve, reject) => { - Services.wm.addListener({ - onOpenWindow(xulWin) { - Services.wm.removeListener(this); - let win = xulWin.docShell.domWindow; - waitForFocus(() => { - if ( - win.location == - "chrome://mozapps/content/downloads/unknownContentType.xhtml" - ) { - let dialog = win.document.getElementById("unknownContentType"); - let button = dialog.getButton("accept"); - let actionRadio = win.document.getElementById(action); - actionRadio.click(); - button.disabled = false; - dialog.acceptDialog(); - resolve(); - } else { - reject(); - } - }, win); - }, - }); - }); - } - return new Promise(res => { - downloadMonitoringView.waitForDownload(res); - }); -} - -const CONSOLE_ERROR_MESSAGE = "We blocked a download that’s not secure"; - -function shouldConsoleError() { - // Waits until CONSOLE_ERROR_MESSAGE was logged - return new Promise((resolve, reject) => { - function listener(msgObj) { - let text = msgObj.message; - if (text.includes(CONSOLE_ERROR_MESSAGE)) { - Services.console.unregisterListener(listener); - resolve(); - } - } - Services.console.registerListener(listener); - }); -} - -async function resetDownloads() { - // Removes all downloads from the download List - const types = new Set(); - let publicList = await Downloads.getList(Downloads.PUBLIC); - let downloads = await publicList.getAll(); - for (let download of downloads) { - if (download.contentType) { - types.add(download.contentType); - } - publicList.remove(download); - await download.finalize(true); - } - - if (types.size) { - // reset handlers for the contentTypes of any files previously downloaded - for (let type of types) { - const mimeInfo = MIMEService.getFromTypeAndExtension(type, ""); - info("resetting handler for type: " + type); - HandlerService.remove(mimeInfo); - } - } -} - -function shouldNotifyDownloadUI() { - return new Promise(res => { - downloadMonitoringView.waitForDownload(async aDownload => { - let { error } = aDownload; - if ( - error.becauseBlockedByReputationCheck && - error.reputationCheckVerdict == Downloads.Error.BLOCK_VERDICT_INSECURE - ) { - // It's an insecure Download, now Check that it has been cleaned up properly - if ((await IOUtils.stat(aDownload.target.path)).size != 0) { - throw new Error(`Download target is not empty!`); - } - if ((await IOUtils.stat(aDownload.target.path)).size != 0) { - throw new Error(`Download partFile was not cleaned up properly`); - } - // Assert that the Referrer is presnt - if (!aDownload.source.referrerInfo) { - throw new Error("The Blocked download is missing the ReferrerInfo"); - } - - res(aDownload); - } else { - ok(false, "No error for download that was expected to error!"); - } - }); - }); -} - -async function runTest(url, link, checkFunction, description) { - await SpecialPowers.pushPrefEnv({ - set: [["dom.block_download_insecure", true]], - }); - await resetDownloads(); - - let tab = BrowserTestUtils.addTab(gBrowser, url); - gBrowser.selectedTab = tab; - - let browser = gBrowser.getBrowserForTab(tab); - await BrowserTestUtils.browserLoaded(browser); - - info("Checking: " + description); - - let checkPromise = checkFunction(); - // Click the Link to trigger the download - SpecialPowers.spawn(gBrowser.selectedBrowser, [link], contentLink => { - content.document.getElementById(contentLink).click(); - }); - - await checkPromise; - - ok(true, description); - BrowserTestUtils.removeTab(tab); - - await SpecialPowers.popPrefEnv(); -} - -add_setup(async () => { - let list = await Downloads.getList(Downloads.ALL); - list.addView(downloadMonitoringView); - registerCleanupFunction(() => list.removeView(downloadMonitoringView)); -}); - -// Test Blocking -add_task(async function test_blocking() { - for (let prefVal of [true, false]) { - await SpecialPowers.pushPrefEnv({ - set: [["browser.download.always_ask_before_handling_new_types", prefVal]], - }); - await runTest( - INSECURE_BASE_URL, - "http-link", - () => - Promise.all([ - shouldTriggerDownload(), - shouldNotifyDownloadUI(), - shouldConsoleError(), - ]), - "Insecure (HTTP) toplevel -> Insecure (HTTP) download should Error" - ); - await SpecialPowers.popPrefEnv(); - } -}); - -// Test Manual Unblocking -add_task(async function test_manual_unblocking() { - for (let prefVal of [true, false]) { - await SpecialPowers.pushPrefEnv({ - set: [["browser.download.always_ask_before_handling_new_types", prefVal]], - }); - await runTest( - INSECURE_BASE_URL, - "http-link", - async () => { - let [, download] = await Promise.all([ - shouldTriggerDownload(), - shouldNotifyDownloadUI(), - ]); - await download.unblock(); - Assert.equal( - download.error, - null, - "There should be no error after unblocking" - ); - }, - "A blocked download should succeed to download after a manual unblock" - ); - await SpecialPowers.popPrefEnv(); - } -}); - -// Test Unblock Download Visible -add_task(async function test_unblock_download_visible() { - for (let prefVal of [true, false]) { - await SpecialPowers.pushPrefEnv({ - set: [["browser.download.always_ask_before_handling_new_types", prefVal]], - }); - await promiseFocus(); - await runTest( - INSECURE_BASE_URL, - "http-link", - async () => { - let panelHasOpened = BrowserTestUtils.waitForPopupEvent( - DownloadsPanel.panel, - "shown" - ); - info("awaiting that the download is triggered and added to the list"); - await Promise.all([shouldTriggerDownload(), shouldNotifyDownloadUI()]); - info("awaiting that the Download list shows itself"); - await panelHasOpened; - DownloadsPanel.hidePanel(); - ok(true, "The Download Panel should have opened on blocked download"); - }, - "A blocked download should open the download panel" - ); - await SpecialPowers.popPrefEnv(); - } -}); diff --git a/dom/security/test/general/http_download_page.html b/dom/security/test/general/http_download_page.html deleted file mode 100644 index c5461eaed3..0000000000 --- a/dom/security/test/general/http_download_page.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - Test for the download attribute - - - hi - - - - diff --git a/dom/security/test/general/http_download_server.sjs b/dom/security/test/general/http_download_server.sjs deleted file mode 100644 index e659df2f40..0000000000 --- a/dom/security/test/general/http_download_server.sjs +++ /dev/null @@ -1,20 +0,0 @@ -// force the Browser to Show a Download Prompt - -function handleRequest(request, response) { - let type = "image/png"; - let filename = "hello.png"; - request.queryString.split("&").forEach(val => { - var [key, value] = val.split("="); - if (key == "type") { - type = value; - } - if (key == "name") { - filename = value; - } - }); - - response.setHeader("Cache-Control", "no-cache", false); - response.setHeader("Content-Disposition", `attachment; filename=${filename}`); - response.setHeader("Content-Type", type); - response.write("🙈🙊🐵🙊"); -} diff --git a/dom/security/test/https-only/browser_save_as.js b/dom/security/test/https-only/browser_save_as.js index fbfdf276a8..28f3df539d 100644 --- a/dom/security/test/https-only/browser_save_as.js +++ b/dom/security/test/https-only/browser_save_as.js @@ -155,11 +155,7 @@ async function setHttpsFirstAndOnlyPrefs(httpsFirst, httpsOnly) { add_task(async function testBaseline() { // Run with HTTPS-First and HTTPS-Only disabled await setHttpsFirstAndOnlyPrefs(false, false); - await runTest( - "#insecure-link", - HTTP_LINK, - "We blocked a download that’s not secure: “http://example.org/”." - ); + await runTest("#insecure-link", HTTP_LINK, undefined); await runTest("#secure-link", HTTPS_LINK, undefined); }); @@ -173,7 +169,7 @@ add_task(async function testHttpsFirst() { await runTest( "#insecure-link", HTTP_LINK, - "We blocked a download that’s not secure: “http://example.org/”." + "Blocked downloading insecure content “http://example.org/”." ); await runTest("#secure-link", HTTPS_LINK, undefined); }); @@ -185,7 +181,7 @@ add_task(async function testHttpsOnly() { await runTest( "#insecure-link", HTTP_LINK, - "We blocked a download that’s not secure: “http://example.org/”." + "Blocked downloading insecure content “http://example.org/”." ); await runTest("#secure-link", HTTPS_LINK, undefined); }); diff --git a/dom/security/test/mixedcontentblocker/browser_test_mixed_content_download.js b/dom/security/test/mixedcontentblocker/browser_test_mixed_content_download.js index b103d83cd7..ee350008aa 100644 --- a/dom/security/test/mixedcontentblocker/browser_test_mixed_content_download.js +++ b/dom/security/test/mixedcontentblocker/browser_test_mixed_content_download.js @@ -101,7 +101,7 @@ function shouldTriggerDownload(action = "save") { }); } -const CONSOLE_ERROR_MESSAGE = "We blocked a download that’s not secure"; +const CONSOLE_ERROR_MESSAGE = "Blocked downloading insecure content"; function shouldConsoleError() { // Waits until CONSOLE_ERROR_MESSAGE was logged diff --git a/dom/serviceworkers/test/browser_download.js b/dom/serviceworkers/test/browser_download.js index 70622a2349..0c69a48d17 100644 --- a/dom/serviceworkers/test/browser_download.js +++ b/dom/serviceworkers/test/browser_download.js @@ -3,7 +3,7 @@ var gTestRoot = getRootDirectory(gTestPath).replace( "chrome://mochitests/content/", - "https://example.com/" + "http://mochi.test:8888/" ); function getFile(aFilename) { -- cgit v1.2.3