ma1 pushed to branch base-browser-128.13.0esr-14.5-1 at The Tor Project / Applications / Tor Browser
Commits:
-
16d48c99
by Cathy Lu at 2025-07-22T01:59:35+02:00
-
2ac18296
by Tom Schuster at 2025-07-22T01:59:37+02:00
-
6221ed58
by Tom Schuster at 2025-07-22T01:59:38+02:00
-
00cf1f42
by Andreas Pehrson at 2025-07-22T01:59:40+02:00
-
7581b39d
by Tom Schuster at 2025-07-22T01:59:41+02:00
-
15787e0c
by Pier Angelo Vendrame at 2025-07-22T01:59:43+02:00
9 changed files:
- dom/media/MediaManager.cpp
- dom/security/nsContentSecurityUtils.cpp
- dom/security/nsContentSecurityUtils.h
- dom/xslt/xpath/txXPathNode.h
- dom/xslt/xslt/txNodeSorter.cpp
- mobile/android/components/geckoview/GeckoViewStreamListener.cpp
- modules/libpref/init/StaticPrefList.yaml
- + testing/web-platform/tests/content-security-policy/frame-src/frame-src-blocked-path-matching.sub.html
- uriloader/exthandler/nsExternalHelperAppService.cpp
Changes:
... | ... | @@ -3513,7 +3513,9 @@ void MediaManager::OnCameraMute(bool aMute) { |
3513 | 3513 | mCamerasMuted = aMute;
|
3514 | 3514 | // This is safe since we're on main-thread, and the windowlist can only
|
3515 | 3515 | // be added to from the main-thread
|
3516 | - for (const auto& window : mActiveWindows.Values()) {
|
|
3516 | + for (const auto& window :
|
|
3517 | + ToTArray<AutoTArray<RefPtr<GetUserMediaWindowListener>, 2>>(
|
|
3518 | + mActiveWindows.Values())) {
|
|
3517 | 3519 | window->MuteOrUnmuteCameras(aMute);
|
3518 | 3520 | }
|
3519 | 3521 | }
|
... | ... | @@ -3524,7 +3526,9 @@ void MediaManager::OnMicrophoneMute(bool aMute) { |
3524 | 3526 | mMicrophonesMuted = aMute;
|
3525 | 3527 | // This is safe since we're on main-thread, and the windowlist can only
|
3526 | 3528 | // be added to from the main-thread
|
3527 | - for (const auto& window : mActiveWindows.Values()) {
|
|
3529 | + for (const auto& window :
|
|
3530 | + ToTArray<AutoTArray<RefPtr<GetUserMediaWindowListener>, 2>>(
|
|
3531 | + mActiveWindows.Values())) {
|
|
3528 | 3532 | window->MuteOrUnmuteMicrophones(aMute);
|
3529 | 3533 | }
|
3530 | 3534 | }
|
... | ... | @@ -4698,7 +4702,7 @@ void GetUserMediaWindowListener::MuteOrUnmuteCameras(bool aMute) { |
4698 | 4702 | }
|
4699 | 4703 | mCamerasAreMuted = aMute;
|
4700 | 4704 | |
4701 | - for (auto& l : mActiveListeners) {
|
|
4705 | + for (auto& l : mActiveListeners.Clone()) {
|
|
4702 | 4706 | if (l->GetDevice()->Kind() == MediaDeviceKind::Videoinput) {
|
4703 | 4707 | l->MuteOrUnmuteCamera(aMute);
|
4704 | 4708 | }
|
... | ... | @@ -4713,7 +4717,7 @@ void GetUserMediaWindowListener::MuteOrUnmuteMicrophones(bool aMute) { |
4713 | 4717 | }
|
4714 | 4718 | mMicrophonesAreMuted = aMute;
|
4715 | 4719 | |
4716 | - for (auto& l : mActiveListeners) {
|
|
4720 | + for (auto& l : mActiveListeners.Clone()) {
|
|
4717 | 4721 | if (l->GetDevice()->Kind() == MediaDeviceKind::Audioinput) {
|
4718 | 4722 | l->MuteOrUnmuteMicrophone(aMute);
|
4719 | 4723 | }
|
... | ... | @@ -1663,11 +1663,17 @@ void nsContentSecurityUtils::LogMessageToConsole(nsIHttpChannel* aChannel, |
1663 | 1663 | }
|
1664 | 1664 | |
1665 | 1665 | /* static */
|
1666 | -long nsContentSecurityUtils::ClassifyDownload(
|
|
1667 | - nsIChannel* aChannel, const nsAutoCString& aMimeTypeGuess) {
|
|
1666 | +long nsContentSecurityUtils::ClassifyDownload(nsIChannel* aChannel) {
|
|
1668 | 1667 | MOZ_ASSERT(aChannel, "IsDownloadAllowed without channel?");
|
1669 | 1668 | |
1670 | 1669 | nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
|
1670 | + if ((loadInfo->GetTriggeringSandboxFlags() & SANDBOXED_ALLOW_DOWNLOADS) ||
|
|
1671 | + (loadInfo->GetSandboxFlags() & SANDBOXED_ALLOW_DOWNLOADS)) {
|
|
1672 | + if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel)) {
|
|
1673 | + LogMessageToConsole(httpChannel, "IframeSandboxBlockedDownload");
|
|
1674 | + }
|
|
1675 | + return nsITransfer::DOWNLOAD_FORBIDDEN;
|
|
1676 | + }
|
|
1671 | 1677 | |
1672 | 1678 | nsCOMPtr<nsIURI> contentLocation;
|
1673 | 1679 | aChannel->GetURI(getter_AddRefs(contentLocation));
|
... | ... | @@ -1698,27 +1704,11 @@ long nsContentSecurityUtils::ClassifyDownload( |
1698 | 1704 | |
1699 | 1705 | if (StaticPrefs::dom_block_download_insecure() &&
|
1700 | 1706 | decission != nsIContentPolicy::ACCEPT) {
|
1701 | - nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
|
|
1702 | - if (httpChannel) {
|
|
1707 | + if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel)) {
|
|
1703 | 1708 | LogMessageToConsole(httpChannel, "MixedContentBlockedDownload");
|
1704 | 1709 | }
|
1705 | 1710 | return nsITransfer::DOWNLOAD_POTENTIALLY_UNSAFE;
|
1706 | 1711 | }
|
1707 | 1712 | |
1708 | - if (loadInfo->TriggeringPrincipal()->IsSystemPrincipal()) {
|
|
1709 | - return nsITransfer::DOWNLOAD_ACCEPTABLE;
|
|
1710 | - }
|
|
1711 | - |
|
1712 | - uint32_t triggeringFlags = loadInfo->GetTriggeringSandboxFlags();
|
|
1713 | - uint32_t currentflags = loadInfo->GetSandboxFlags();
|
|
1714 | - |
|
1715 | - if ((triggeringFlags & SANDBOXED_ALLOW_DOWNLOADS) ||
|
|
1716 | - (currentflags & SANDBOXED_ALLOW_DOWNLOADS)) {
|
|
1717 | - nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
|
|
1718 | - if (httpChannel) {
|
|
1719 | - LogMessageToConsole(httpChannel, "IframeSandboxBlockedDownload");
|
|
1720 | - }
|
|
1721 | - return nsITransfer::DOWNLOAD_FORBIDDEN;
|
|
1722 | - }
|
|
1723 | 1713 | return nsITransfer::DOWNLOAD_ACCEPTABLE;
|
1724 | 1714 | } |
... | ... | @@ -75,8 +75,7 @@ class nsContentSecurityUtils { |
75 | 75 | const mozilla::dom::Element& aElement);
|
76 | 76 | |
77 | 77 | // Helper function to Check if a Download is allowed;
|
78 | - static long ClassifyDownload(nsIChannel* aChannel,
|
|
79 | - const nsAutoCString& aMimeTypeGuess);
|
|
78 | + static long ClassifyDownload(nsIChannel* aChannel);
|
|
80 | 79 | |
81 | 80 | // Public only for testing
|
82 | 81 | static FilenameTypeAndDetails FilenameToFilenameType(
|
... | ... | @@ -66,6 +66,8 @@ class txXPathNode { |
66 | 66 | bool operator!=(const txXPathNode& aNode) const { return !(*this == aNode); }
|
67 | 67 | ~txXPathNode() { MOZ_COUNT_DTOR(txXPathNode); }
|
68 | 68 | |
69 | + mozilla::dom::Document* OwnerDoc() const { return mNode->OwnerDoc(); }
|
|
70 | + |
|
69 | 71 | private:
|
70 | 72 | friend class txXPathNativeNode;
|
71 | 73 | friend class txXPathNodeUtils;
|
... | ... | @@ -13,10 +13,13 @@ |
13 | 13 | |
14 | 14 | #include "mozilla/CheckedInt.h"
|
15 | 15 | #include "mozilla/UniquePtrExtensions.h"
|
16 | +#include "nsRFPService.h"
|
|
16 | 17 | |
17 | 18 | using mozilla::CheckedUint32;
|
18 | 19 | using mozilla::MakeUnique;
|
19 | 20 | using mozilla::MakeUniqueFallible;
|
21 | +using mozilla::nsRFPService;
|
|
22 | +using mozilla::RFPTarget;
|
|
20 | 23 | using mozilla::UniquePtr;
|
21 | 24 | |
22 | 25 | /*
|
... | ... | @@ -74,6 +77,10 @@ nsresult txNodeSorter::addSortElement(Expr* aSelectExpr, Expr* aLangExpr, |
74 | 77 | if (aLangExpr) {
|
75 | 78 | rv = aLangExpr->evaluateToString(aContext, lang);
|
76 | 79 | NS_ENSURE_SUCCESS(rv, rv);
|
80 | + } else if (aContext->getContextNode()
|
|
81 | + .OwnerDoc()
|
|
82 | + ->ShouldResistFingerprinting(RFPTarget::JSLocale)) {
|
|
83 | + CopyUTF8toUTF16(nsRFPService::GetSpoofedJSLocale(), lang);
|
|
77 | 84 | }
|
78 | 85 | |
79 | 86 | // Case-order
|
... | ... | @@ -16,6 +16,8 @@ |
16 | 16 | #include "nsIWebProgressListener.h"
|
17 | 17 | #include "nsIX509Cert.h"
|
18 | 18 | #include "nsPrintfCString.h"
|
19 | +#include "nsContentSecurityUtils.h"
|
|
20 | +#include "nsITransfer.h"
|
|
19 | 21 | |
20 | 22 | #include "nsNetUtil.h"
|
21 | 23 | |
... | ... | @@ -85,6 +87,16 @@ GeckoViewStreamListener::OnStartRequest(nsIRequest* aRequest) { |
85 | 87 | return NS_OK;
|
86 | 88 | }
|
87 | 89 | |
90 | + nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
|
|
91 | + if (channel) {
|
|
92 | + int32_t classification = nsContentSecurityUtils::ClassifyDownload(channel);
|
|
93 | + if (classification == nsITransfer::DOWNLOAD_FORBIDDEN) {
|
|
94 | + channel->Cancel(NS_ERROR_ABORT);
|
|
95 | + CompleteWithError(NS_ERROR_ABORT, channel);
|
|
96 | + return NS_OK;
|
|
97 | + }
|
|
98 | + }
|
|
99 | + |
|
88 | 100 | // We're expecting data later via OnDataAvailable, so create the stream now.
|
89 | 101 | InitializeStreamSupport(aRequest);
|
90 | 102 |
... | ... | @@ -14658,7 +14658,7 @@ |
14658 | 14658 | |
14659 | 14659 | - name: security.csp.truncate_blocked_uri_for_frame_navigations
|
14660 | 14660 | type: bool
|
14661 | - value: true
|
|
14661 | + value: false
|
|
14662 | 14662 | mirror: always
|
14663 | 14663 | |
14664 | 14664 | # Limit the number of CSP reports that are send in a specific timespan.
|
1 | +<!DOCTYPE html>
|
|
2 | +<html>
|
|
3 | +<head>
|
|
4 | + <!-- Make sure frame-src does path matching -->
|
|
5 | + <meta http-equiv="Content-Security-Policy" content="frame-src data: https://{{hosts[][www1]}}:{{ports[https][0]}}/content-security-policy/support/;">
|
|
6 | + <title>frame-src-blocked-path-matching</title>
|
|
7 | + <script src="/resources/testharness.js"></script>
|
|
8 | + <script src="/resources/testharnessreport.js"></script>
|
|
9 | +</head>
|
|
10 | +<body>
|
|
11 | + <script>
|
|
12 | + async_test(t => {
|
|
13 | + let frame = document.createElement("iframe");
|
|
14 | + frame.src = "https://{{hosts[][www1]}}:{{ports[https][0]}}/content-security-policy/support/postmessage-pass.html";
|
|
15 | + |
|
16 | + window.addEventListener('message', t.step_func(e => {
|
|
17 | + if (e.source === frame.contentWindow) {
|
|
18 | + assert_equals(e.data, "PASS");
|
|
19 | + t.done();
|
|
20 | + }
|
|
21 | + }));
|
|
22 | + |
|
23 | + document.body.append(frame);
|
|
24 | + }, "Cross-origin frame with allowed path loads");
|
|
25 | + |
|
26 | + async_test(t => {
|
|
27 | + let frame = document.createElement("iframe");
|
|
28 | + frame.src = "https://{{hosts[][www1]}}:{{ports[https][0]}}/content-security-policy/resource/";
|
|
29 | + |
|
30 | + window.addEventListener('securitypolicyviolation', t.step_func_done(e => {
|
|
31 | + assert_equals(e.blockedURI, "https://{{hosts[][www1]}}:{{ports[https][0]}}");
|
|
32 | + assert_equals(e.effectiveDirective, "frame-src");
|
|
33 | + }), { once: true });
|
|
34 | + |
|
35 | + document.body.append(frame);
|
|
36 | + }, "Cross-origin frame with other path is blocked");
|
|
37 | + |
|
38 | + async_test(t => {
|
|
39 | + let frame = document.createElement("iframe");
|
|
40 | + frame.src = "data:text/html,<h1>Hello World</h1>"
|
|
41 | + frame.onload = t.step_func(() => {
|
|
42 | + frame.src = "https://{{hosts[][www1]}}:{{ports[https][0]}}/content-security-policy/resource/";
|
|
43 | + |
|
44 | + window.addEventListener('securitypolicyviolation', t.step_func_done(e => {
|
|
45 | + assert_equals(e.blockedURI, "https://{{hosts[][www1]}}:{{ports[https][0]}}");
|
|
46 | + assert_equals(e.effectiveDirective, "frame-src");
|
|
47 | + }), { once: true });
|
|
48 | + });
|
|
49 | + document.body.append(frame);
|
|
50 | + }, "Cross-origin frame with other path is blocked even after replacing the already loaded URL");
|
|
51 | + </script>
|
|
52 | + </body>
|
|
53 | +</html> |
... | ... | @@ -1584,8 +1584,7 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { |
1584 | 1584 | return NS_OK;
|
1585 | 1585 | }
|
1586 | 1586 | |
1587 | - mDownloadClassification =
|
|
1588 | - nsContentSecurityUtils::ClassifyDownload(aChannel, MIMEType);
|
|
1587 | + mDownloadClassification = nsContentSecurityUtils::ClassifyDownload(aChannel);
|
|
1589 | 1588 | |
1590 | 1589 | if (mDownloadClassification == nsITransfer::DOWNLOAD_FORBIDDEN) {
|
1591 | 1590 | // If the download is rated as forbidden,
|