ma1 pushed to branch tor-browser-115.26.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
-
5bf16ee7
by Tom Schuster at 2025-07-19T00:29:10+02:00
-
8f1a16c0
by Tom Schuster at 2025-07-19T00:29:21+02:00
-
cd18dbf5
by Hubert Boma Manilla at 2025-07-21T20:07:18+02:00
-
449e7d2c
by vyv03354 at 2025-07-21T23:13:43+02:00
-
96d7c8c5
by Andreas Pehrson at 2025-07-21T23:24:28+02:00
-
c3a28639
by Pier Angelo Vendrame at 2025-07-22T00:43:11+02:00
8 changed files:
- devtools/client/netmonitor/test/browser_net_curl-utils.js
- devtools/client/shared/curl.js
- dom/base/nsObjectLoadingContent.cpp
- dom/media/MediaManager.cpp
- dom/xslt/xpath/txXPathNode.h
- dom/xslt/xslt/txNodeSorter.cpp
- modules/libpref/init/StaticPrefList.yaml
- + testing/web-platform/tests/content-security-policy/frame-src/frame-src-blocked-path-matching.sub.html
Changes:
... | ... | @@ -344,7 +344,7 @@ function testEscapeStringWin() { |
344 | 344 | const newLines = "line1\r\nline2\r\rline3\n\nline4";
|
345 | 345 | is(
|
346 | 346 | CurlUtils.escapeStringWin(newLines),
|
347 | - '^"line1^\n\nline2\r\rline3^\n\n^\n\nline4^"',
|
|
347 | + '^\"line1^\n\nline2^\n\n^\n\nline3^\n\n^\n\nline4^\"',
|
|
348 | 348 | "Newlines should be escaped."
|
349 | 349 | );
|
350 | 350 | |
... | ... | @@ -365,7 +365,7 @@ function testEscapeStringWin() { |
365 | 365 | const evilCommand = `query=evil\r\rcmd" /c timeout /t 3 & calc.exe\r\r`;
|
366 | 366 | is(
|
367 | 367 | CurlUtils.escapeStringWin(evilCommand),
|
368 | - '^"query=evil\r\rcmd\\" /c timeout /t 3 & calc.exe\r\r^"',
|
|
368 | + '^\"query=evil^\n\n^\n\ncmd\\\" /c timeout /t 3 & calc.exe^\n\n^\n\n^\"',
|
|
369 | 369 | "The evil command is escaped properly"
|
370 | 370 | );
|
371 | 371 | }
|
... | ... | @@ -484,7 +484,7 @@ const CurlUtils = { |
484 | 484 | // Lastly we replace new lines with ^ and TWO new lines because the first
|
485 | 485 | // new line is there to enact the escape command the second is the character
|
486 | 486 | // to escape (in this case new line).
|
487 | - .replace(/\r?\n/g, "^\n\n") +
|
|
487 | + .replace(/\r?\n|\r/g, "^\n\n") +
|
|
488 | 488 | encapsChars
|
489 | 489 | );
|
490 | 490 | },
|
... | ... | @@ -750,8 +750,8 @@ void nsObjectLoadingContent::MaybeRewriteYoutubeEmbed(nsIURI* aURI, |
750 | 750 | }
|
751 | 751 | |
752 | 752 | // See if requester is planning on using the JS API.
|
753 | - nsAutoCString uri;
|
|
754 | - nsresult rv = aURI->GetSpec(uri);
|
|
753 | + nsAutoCString prePath;
|
|
754 | + nsresult rv = aURI->GetPrePath(prePath);
|
|
755 | 755 | if (NS_FAILED(rv)) {
|
756 | 756 | return;
|
757 | 757 | }
|
... | ... | @@ -762,10 +762,10 @@ void nsObjectLoadingContent::MaybeRewriteYoutubeEmbed(nsIURI* aURI, |
762 | 762 | // URLs, convert the parameters to query in order to make the video load
|
763 | 763 | // correctly as an iframe. In either case, warn about it in the
|
764 | 764 | // developer console.
|
765 | - int32_t ampIndex = uri.FindChar('&', 0);
|
|
765 | + int32_t ampIndex = path.FindChar('&', 0);
|
|
766 | 766 | bool replaceQuery = false;
|
767 | 767 | if (ampIndex != -1) {
|
768 | - int32_t qmIndex = uri.FindChar('?', 0);
|
|
768 | + int32_t qmIndex = path.FindChar('?', 0);
|
|
769 | 769 | if (qmIndex == -1 || qmIndex > ampIndex) {
|
770 | 770 | replaceQuery = true;
|
771 | 771 | }
|
... | ... | @@ -776,21 +776,23 @@ void nsObjectLoadingContent::MaybeRewriteYoutubeEmbed(nsIURI* aURI, |
776 | 776 | return;
|
777 | 777 | }
|
778 | 778 | |
779 | - nsAutoString utf16OldURI = NS_ConvertUTF8toUTF16(uri);
|
|
779 | + NS_ConvertUTF8toUTF16 utf16OldURI(prePath);
|
|
780 | + AppendUTF8toUTF16(path, utf16OldURI);
|
|
780 | 781 | // If we need to convert the URL, it means an ampersand comes first.
|
781 | 782 | // Use the index we found earlier.
|
782 | 783 | if (replaceQuery) {
|
783 | 784 | // Replace question marks with ampersands.
|
784 | - uri.ReplaceChar('?', '&');
|
|
785 | + path.ReplaceChar('?', '&');
|
|
785 | 786 | // Replace the first ampersand with a question mark.
|
786 | - uri.SetCharAt('?', ampIndex);
|
|
787 | + path.SetCharAt('?', ampIndex);
|
|
787 | 788 | }
|
788 | 789 | // Switch out video access url formats, which should possibly allow HTML5
|
789 | 790 | // video loading.
|
790 | - uri.ReplaceSubstring("/v/"_ns, "/embed/"_ns);
|
|
791 | - nsAutoString utf16URI = NS_ConvertUTF8toUTF16(uri);
|
|
792 | - rv = nsContentUtils::NewURIWithDocumentCharset(
|
|
793 | - aRewrittenURI, utf16URI, thisContent->OwnerDoc(), aBaseURI);
|
|
791 | + path.ReplaceSubstring("/v/"_ns, "/embed/"_ns);
|
|
792 | + NS_ConvertUTF8toUTF16 utf16URI(prePath);
|
|
793 | + AppendUTF8toUTF16(path, utf16URI);
|
|
794 | + rv = nsContentUtils::NewURIWithDocumentCharset(aRewrittenURI, utf16URI, doc,
|
|
795 | + aBaseURI);
|
|
794 | 796 | if (NS_FAILED(rv)) {
|
795 | 797 | return;
|
796 | 798 | }
|
... | ... | @@ -3143,7 +3143,9 @@ void MediaManager::OnCameraMute(bool aMute) { |
3143 | 3143 | mCamerasMuted = aMute;
|
3144 | 3144 | // This is safe since we're on main-thread, and the windowlist can only
|
3145 | 3145 | // be added to from the main-thread
|
3146 | - for (const auto& window : mActiveWindows.Values()) {
|
|
3146 | + for (const auto& window :
|
|
3147 | + ToTArray<AutoTArray<RefPtr<GetUserMediaWindowListener>, 2>>(
|
|
3148 | + mActiveWindows.Values())) {
|
|
3147 | 3149 | window->MuteOrUnmuteCameras(aMute);
|
3148 | 3150 | }
|
3149 | 3151 | }
|
... | ... | @@ -3154,7 +3156,9 @@ void MediaManager::OnMicrophoneMute(bool aMute) { |
3154 | 3156 | mMicrophonesMuted = aMute;
|
3155 | 3157 | // This is safe since we're on main-thread, and the windowlist can only
|
3156 | 3158 | // be added to from the main-thread
|
3157 | - for (const auto& window : mActiveWindows.Values()) {
|
|
3159 | + for (const auto& window :
|
|
3160 | + ToTArray<AutoTArray<RefPtr<GetUserMediaWindowListener>, 2>>(
|
|
3161 | + mActiveWindows.Values())) {
|
|
3158 | 3162 | window->MuteOrUnmuteMicrophones(aMute);
|
3159 | 3163 | }
|
3160 | 3164 | }
|
... | ... | @@ -4340,7 +4344,7 @@ void GetUserMediaWindowListener::MuteOrUnmuteCameras(bool aMute) { |
4340 | 4344 | }
|
4341 | 4345 | mCamerasAreMuted = aMute;
|
4342 | 4346 | |
4343 | - for (auto& l : mActiveListeners) {
|
|
4347 | + for (auto& l : mActiveListeners.Clone()) {
|
|
4344 | 4348 | if (l->GetDevice()->Kind() == MediaDeviceKind::Videoinput) {
|
4345 | 4349 | l->MuteOrUnmuteCamera(aMute);
|
4346 | 4350 | }
|
... | ... | @@ -4355,7 +4359,7 @@ void GetUserMediaWindowListener::MuteOrUnmuteMicrophones(bool aMute) { |
4355 | 4359 | }
|
4356 | 4360 | mMicrophonesAreMuted = aMute;
|
4357 | 4361 | |
4358 | - for (auto& l : mActiveListeners) {
|
|
4362 | + for (auto& l : mActiveListeners.Clone()) {
|
|
4359 | 4363 | if (l->GetDevice()->Kind() == MediaDeviceKind::Audioinput) {
|
4360 | 4364 | l->MuteOrUnmuteMicrophone(aMute);
|
4361 | 4365 | }
|
... | ... | @@ -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;
|
... | ... | @@ -14,10 +14,13 @@ |
14 | 14 | |
15 | 15 | #include "mozilla/CheckedInt.h"
|
16 | 16 | #include "mozilla/UniquePtrExtensions.h"
|
17 | +#include "nsRFPService.h"
|
|
17 | 18 | |
18 | 19 | using mozilla::CheckedUint32;
|
19 | 20 | using mozilla::MakeUnique;
|
20 | 21 | using mozilla::MakeUniqueFallible;
|
22 | +using mozilla::nsRFPService;
|
|
23 | +using mozilla::RFPTarget;
|
|
21 | 24 | using mozilla::UniquePtr;
|
22 | 25 | |
23 | 26 | /*
|
... | ... | @@ -75,6 +78,10 @@ nsresult txNodeSorter::addSortElement(Expr* aSelectExpr, Expr* aLangExpr, |
75 | 78 | if (aLangExpr) {
|
76 | 79 | rv = aLangExpr->evaluateToString(aContext, lang);
|
77 | 80 | NS_ENSURE_SUCCESS(rv, rv);
|
81 | + } else if (aContext->getContextNode()
|
|
82 | + .OwnerDoc()
|
|
83 | + ->ShouldResistFingerprinting(RFPTarget::JSLocale)) {
|
|
84 | + CopyUTF8toUTF16(nsRFPService::GetSpoofedJSLocale(), lang);
|
|
78 | 85 | }
|
79 | 86 | |
80 | 87 | // Case-order
|
... | ... | @@ -13671,7 +13671,7 @@ |
13671 | 13671 | |
13672 | 13672 | - name: security.csp.truncate_blocked_uri_for_frame_navigations
|
13673 | 13673 | type: bool
|
13674 | - value: true
|
|
13674 | + value: false
|
|
13675 | 13675 | mirror: always
|
13676 | 13676 | |
13677 | 13677 | # If true, all toplevel data: URI navigations will be blocked.
|
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> |