ma1 pushed to branch mullvad-browser-128.14.0esr-14.5-1 at The Tor Project / Applications / Mullvad Browser
Commits:
-
febf4c83
by Emma Zuehlcke at 2025-09-15T22:21:22+02:00
-
cc301f19
by Daniel Holbert at 2025-09-15T22:21:23+02:00
-
111779ce
by Makoto Kato at 2025-09-15T22:21:25+02:00
-
4c25597a
by Jon Coppeard at 2025-09-15T22:21:26+02:00
-
ea3d5632
by longsonr at 2025-09-15T22:21:28+02:00
-
ecda78b0
by Lee Salzman at 2025-09-15T22:21:29+02:00
-
aee1e3a4
by Jed Davis at 2025-09-15T22:21:30+02:00
-
58c8b96e
by Lee Salzman at 2025-09-15T22:21:32+02:00
-
67e9d857
by Lee Salzman at 2025-09-15T22:21:33+02:00
-
658910d2
by Lee Salzman at 2025-09-15T22:21:35+02:00
12 changed files:
- browser/locales/en-US/browser/webrtcIndicator.ftl
- browser/modules/webrtcUI.sys.mjs
- dom/canvas/WebGLContext.cpp
- dom/security/nsContentSecurityManager.cpp
- gfx/2d/FilterProcessingScalar.cpp
- gfx/2d/InlineTranslator.h
- gfx/layers/ipc/CanvasTranslator.cpp
- js/src/gc/Statistics.cpp
- layout/printing/PrintTranslator.h
- mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/IntentUtils.java
- modules/libpref/init/StaticPrefList.yaml
- security/sandbox/linux/launch/SandboxLaunch.cpp
Changes:
| ... | ... | @@ -60,7 +60,7 @@ webrtc-screen-system-menu = |
| 60 | 60 | ## These strings are only used on Mac for menus attached to icons
|
| 61 | 61 | ## near the clock on the mac menubar.
|
| 62 | 62 | ## Variables:
|
| 63 | -## $streamTitle (String): the title of the tab using the share.
|
|
| 63 | +## $streamTitle (String): the host of the tab using the share.
|
|
| 64 | 64 | ## $tabCount (Number): the title of the tab using the share.
|
| 65 | 65 | |
| 66 | 66 | webrtc-indicator-menuitem-control-sharing =
|
| ... | ... | @@ -1048,8 +1048,10 @@ export function showStreamSharingMenu(win, event, inclWindow = false) { |
| 1048 | 1048 | let stream = activeStreams[0];
|
| 1049 | 1049 | |
| 1050 | 1050 | const sharingItem = doc.createXULElement("menuitem");
|
| 1051 | - const streamTitle = stream.browser.contentTitle || stream.uri;
|
|
| 1052 | - doc.l10n.setAttributes(sharingItem, l10nIds[0], { streamTitle });
|
|
| 1051 | + const displayHost = getDisplayHostForStream(stream);
|
|
| 1052 | + doc.l10n.setAttributes(sharingItem, l10nIds[0], {
|
|
| 1053 | + streamTitle: displayHost,
|
|
| 1054 | + });
|
|
| 1053 | 1055 | sharingItem.setAttribute("disabled", "true");
|
| 1054 | 1056 | menu.appendChild(sharingItem);
|
| 1055 | 1057 | |
| ... | ... | @@ -1073,11 +1075,11 @@ export function showStreamSharingMenu(win, event, inclWindow = false) { |
| 1073 | 1075 | |
| 1074 | 1076 | for (let stream of activeStreams) {
|
| 1075 | 1077 | const controlItem = doc.createXULElement("menuitem");
|
| 1076 | - const streamTitle = stream.browser.contentTitle || stream.uri;
|
|
| 1078 | + const displayHost = getDisplayHostForStream(stream);
|
|
| 1077 | 1079 | doc.l10n.setAttributes(
|
| 1078 | 1080 | controlItem,
|
| 1079 | 1081 | "webrtc-indicator-menuitem-control-sharing-on",
|
| 1080 | - { streamTitle }
|
|
| 1082 | + { streamTitle: displayHost }
|
|
| 1081 | 1083 | );
|
| 1082 | 1084 | controlItem.stream = stream;
|
| 1083 | 1085 | controlItem.addEventListener("command", this);
|
| ... | ... | @@ -1086,6 +1088,25 @@ export function showStreamSharingMenu(win, event, inclWindow = false) { |
| 1086 | 1088 | }
|
| 1087 | 1089 | }
|
| 1088 | 1090 | |
| 1091 | +function getDisplayHostForStream(stream) {
|
|
| 1092 | + let uri = Services.io.newURI(stream.uri);
|
|
| 1093 | + |
|
| 1094 | + let displayHost;
|
|
| 1095 | + |
|
| 1096 | + try {
|
|
| 1097 | + displayHost = uri.displayHost;
|
|
| 1098 | + } catch (ex) {
|
|
| 1099 | + displayHost = null;
|
|
| 1100 | + }
|
|
| 1101 | + |
|
| 1102 | + // Host getter threw or returned "". Fall back to spec.
|
|
| 1103 | + if (displayHost == null || displayHost == "") {
|
|
| 1104 | + displayHost = uri.displaySpec;
|
|
| 1105 | + }
|
|
| 1106 | + |
|
| 1107 | + return displayHost;
|
|
| 1108 | +}
|
|
| 1109 | + |
|
| 1089 | 1110 | function onTabSharingMenuPopupShowing(e) {
|
| 1090 | 1111 | const streams = webrtcUI.getActiveStreams(true, true, true, true);
|
| 1091 | 1112 | for (let streamInfo of streams) {
|
| ... | ... | @@ -7,8 +7,9 @@ |
| 7 | 7 | |
| 8 | 8 | #include <algorithm>
|
| 9 | 9 | #include <bitset>
|
| 10 | +#include <cctype>
|
|
| 11 | +#include <iterator>
|
|
| 10 | 12 | #include <queue>
|
| 11 | -#include <regex>
|
|
| 12 | 13 | |
| 13 | 14 | #include "AccessCheck.h"
|
| 14 | 15 | #include "CompositableHost.h"
|
| ... | ... | @@ -2204,30 +2205,59 @@ Maybe<std::string> WebGLContext::GetString(const GLenum pname) const { |
| 2204 | 2205 | // ---------------------------------
|
| 2205 | 2206 | |
| 2206 | 2207 | Maybe<webgl::IndexedName> webgl::ParseIndexed(const std::string& str) {
|
| 2207 | - static const std::regex kRegex("(.*)\\[([0-9]+)\\]");
|
|
| 2208 | - |
|
| 2209 | - std::smatch match;
|
|
| 2210 | - if (!std::regex_match(str, match, kRegex)) return {};
|
|
| 2208 | + // Check if the string ends with a close bracket
|
|
| 2209 | + if (str.size() < 2 || str.back() != ']') {
|
|
| 2210 | + return {};
|
|
| 2211 | + }
|
|
| 2212 | + // Search for the open bracket, only allow digits between brackets
|
|
| 2213 | + const size_t closeBracket = str.size() - 1;
|
|
| 2214 | + size_t openBracket = closeBracket;
|
|
| 2215 | + for (;;) {
|
|
| 2216 | + char c = str[--openBracket];
|
|
| 2217 | + if (isdigit(c)) {
|
|
| 2218 | + if (openBracket <= 0) {
|
|
| 2219 | + // At the beginning of string without an open bracket
|
|
| 2220 | + return {};
|
|
| 2221 | + }
|
|
| 2222 | + } else if (c == '[') {
|
|
| 2223 | + // Found the open bracket
|
|
| 2224 | + break;
|
|
| 2225 | + } else {
|
|
| 2226 | + // Found a non-digit
|
|
| 2227 | + return {};
|
|
| 2228 | + }
|
|
| 2229 | + }
|
|
| 2211 | 2230 | |
| 2212 | - const auto index = std::stoull(match[2]);
|
|
| 2213 | - return Some(webgl::IndexedName{match[1], index});
|
|
| 2231 | + // Ensure non-empty digit sequence
|
|
| 2232 | + size_t firstDigit = openBracket + 1;
|
|
| 2233 | + if (firstDigit >= closeBracket) {
|
|
| 2234 | + return {};
|
|
| 2235 | + }
|
|
| 2236 | + const auto index =
|
|
| 2237 | + std::stoull(str.substr(firstDigit, closeBracket - firstDigit));
|
|
| 2238 | + std::string name = str.substr(0, openBracket);
|
|
| 2239 | + return Some(webgl::IndexedName{name, index});
|
|
| 2214 | 2240 | }
|
| 2215 | 2241 | |
| 2216 | 2242 | // ExplodeName("foo.bar[3].x") -> ["foo", ".", "bar", "[", "3", "]", ".", "x"]
|
| 2217 | 2243 | static std::vector<std::string> ExplodeName(const std::string& str) {
|
| 2218 | 2244 | std::vector<std::string> ret;
|
| 2219 | - |
|
| 2220 | - static const std::regex kSep("[.[\\]]");
|
|
| 2221 | - |
|
| 2222 | - auto itr = std::regex_token_iterator<decltype(str.begin())>(
|
|
| 2223 | - str.begin(), str.end(), kSep, {-1, 0});
|
|
| 2224 | - const auto end = decltype(itr)();
|
|
| 2225 | - |
|
| 2226 | - for (; itr != end; ++itr) {
|
|
| 2227 | - const auto& part = itr->str();
|
|
| 2228 | - if (part.size()) {
|
|
| 2229 | - ret.push_back(part);
|
|
| 2245 | + size_t curPos = 0;
|
|
| 2246 | + while (curPos < str.size()) {
|
|
| 2247 | + // Find the next separator
|
|
| 2248 | + size_t nextPos = str.find_first_of(".[]", curPos);
|
|
| 2249 | + if (nextPos == std::string::npos) {
|
|
| 2250 | + // If no separator found, add remaining substring
|
|
| 2251 | + ret.push_back(str.substr(curPos));
|
|
| 2252 | + break;
|
|
| 2253 | + }
|
|
| 2254 | + // Add string between separators, if not empty
|
|
| 2255 | + if (curPos < nextPos) {
|
|
| 2256 | + ret.push_back(str.substr(curPos, nextPos - curPos));
|
|
| 2230 | 2257 | }
|
| 2258 | + // Add the separator
|
|
| 2259 | + ret.push_back(str.substr(nextPos, 1));
|
|
| 2260 | + curPos = nextPos + 1;
|
|
| 2231 | 2261 | }
|
| 2232 | 2262 | return ret;
|
| 2233 | 2263 | }
|
| ... | ... | @@ -45,6 +45,7 @@ |
| 45 | 45 | #include "mozilla/Logging.h"
|
| 46 | 46 | #include "mozilla/Maybe.h"
|
| 47 | 47 | #include "mozilla/Preferences.h"
|
| 48 | +#include "mozilla/StaticPrefs_content.h"
|
|
| 48 | 49 | #include "mozilla/StaticPrefs_dom.h"
|
| 49 | 50 | #include "mozilla/StaticPrefs_security.h"
|
| 50 | 51 | #include "mozilla/Telemetry.h"
|
| ... | ... | @@ -364,10 +365,17 @@ static nsresult DoCORSChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo, |
| 364 | 365 | return NS_OK;
|
| 365 | 366 | }
|
| 366 | 367 | |
| 367 | - // We use the triggering principal here, rather than the loading principal
|
|
| 368 | - // to ensure that anonymous CORS content in the browser resources and in
|
|
| 369 | - // WebExtensions is allowed to load.
|
|
| 370 | - nsIPrincipal* principal = aLoadInfo->TriggeringPrincipal();
|
|
| 368 | + nsIPrincipal* principal = aLoadInfo->GetLoadingPrincipal();
|
|
| 369 | + if (StaticPrefs::content_cors_use_triggering_principal()) {
|
|
| 370 | + // We use the triggering principal here, rather than the loading principal,
|
|
| 371 | + // to ensure that WebExtensions can reuse their own resources from content
|
|
| 372 | + // that they inject into a page.
|
|
| 373 | + //
|
|
| 374 | + // TODO(dholbert): Is there actually a legitimate reason that WebExtensions
|
|
| 375 | + // might need this (as opposed to exposing their resources for use in
|
|
| 376 | + // web-content via the 'web_accessible_resources' manifest field)?
|
|
| 377 | + principal = aLoadInfo->TriggeringPrincipal();
|
|
| 378 | + }
|
|
| 371 | 379 | RefPtr<nsCORSListenerProxy> corsListener = new nsCORSListenerProxy(
|
| 372 | 380 | aInAndOutListener, principal,
|
| 373 | 381 | aLoadInfo->GetCookiePolicy() == nsILoadInfo::SEC_COOKIES_INCLUDE);
|
| ... | ... | @@ -47,12 +47,12 @@ static void ApplyMorphologyHorizontal_Scalar( |
| 47 | 47 | x++, startX++, endX++) {
|
| 48 | 48 | int32_t sourceIndex = y * aSourceStride + 4 * startX;
|
| 49 | 49 | uint8_t u[4];
|
| 50 | - for (size_t i = 0; i < 4; i++) {
|
|
| 50 | + for (int32_t i = 0; i < int32_t(std::size(u)); i++) {
|
|
| 51 | 51 | u[i] = aSourceData[sourceIndex + i];
|
| 52 | 52 | }
|
| 53 | 53 | sourceIndex += 4;
|
| 54 | 54 | for (int32_t ix = startX + 1; ix <= endX; ix++, sourceIndex += 4) {
|
| 55 | - for (size_t i = 0; i < 4; i++) {
|
|
| 55 | + for (int32_t i = 0; i < int32_t(std::size(u)); i++) {
|
|
| 56 | 56 | if (Operator == MORPHOLOGY_OPERATOR_ERODE) {
|
| 57 | 57 | u[i] = umin(u[i], aSourceData[sourceIndex + i]);
|
| 58 | 58 | } else {
|
| ... | ... | @@ -62,7 +62,7 @@ static void ApplyMorphologyHorizontal_Scalar( |
| 62 | 62 | }
|
| 63 | 63 | |
| 64 | 64 | int32_t destIndex = y * aDestStride + 4 * x;
|
| 65 | - for (size_t i = 0; i < 4; i++) {
|
|
| 65 | + for (int32_t i = 0; i < int32_t(std::size(u)); i++) {
|
|
| 66 | 66 | aDestData[destIndex + i] = u[i];
|
| 67 | 67 | }
|
| 68 | 68 | }
|
| ... | ... | @@ -97,13 +97,13 @@ static void ApplyMorphologyVertical_Scalar( |
| 97 | 97 | for (int32_t x = aDestRect.X(); x < aDestRect.XMost(); x++) {
|
| 98 | 98 | int32_t sourceIndex = startY * aSourceStride + 4 * x;
|
| 99 | 99 | uint8_t u[4];
|
| 100 | - for (size_t i = 0; i < 4; i++) {
|
|
| 100 | + for (int32_t i = 0; i < int32_t(std::size(u)); i++) {
|
|
| 101 | 101 | u[i] = aSourceData[sourceIndex + i];
|
| 102 | 102 | }
|
| 103 | 103 | sourceIndex += aSourceStride;
|
| 104 | 104 | for (int32_t iy = startY + 1; iy <= endY;
|
| 105 | 105 | iy++, sourceIndex += aSourceStride) {
|
| 106 | - for (size_t i = 0; i < 4; i++) {
|
|
| 106 | + for (int32_t i = 0; i < int32_t(std::size(u)); i++) {
|
|
| 107 | 107 | if (Operator == MORPHOLOGY_OPERATOR_ERODE) {
|
| 108 | 108 | u[i] = umin(u[i], aSourceData[sourceIndex + i]);
|
| 109 | 109 | } else {
|
| ... | ... | @@ -113,7 +113,7 @@ static void ApplyMorphologyVertical_Scalar( |
| 113 | 113 | }
|
| 114 | 114 | |
| 115 | 115 | int32_t destIndex = y * aDestStride + 4 * x;
|
| 116 | - for (size_t i = 0; i < 4; i++) {
|
|
| 116 | + for (int32_t i = 0; i < int32_t(std::size(u)); i++) {
|
|
| 117 | 117 | aDestData[destIndex + i] = u[i];
|
| 118 | 118 | }
|
| 119 | 119 | }
|
| ... | ... | @@ -92,7 +92,11 @@ class InlineTranslator : public Translator { |
| 92 | 92 | already_AddRefed<SourceSurface> LookupExternalSurface(uint64_t aKey) override;
|
| 93 | 93 | |
| 94 | 94 | void AddDrawTarget(ReferencePtr aRefPtr, DrawTarget* aDT) final {
|
| 95 | - mDrawTargets.InsertOrUpdate(aRefPtr, RefPtr{aDT});
|
|
| 95 | + RefPtr<DrawTarget>& value = mDrawTargets.LookupOrInsert(aRefPtr);
|
|
| 96 | + if (mCurrentDT && mCurrentDT == value) {
|
|
| 97 | + mCurrentDT = nullptr;
|
|
| 98 | + }
|
|
| 99 | + value = aDT;
|
|
| 96 | 100 | }
|
| 97 | 101 | |
| 98 | 102 | void AddPath(ReferencePtr aRefPtr, Path* aPath) final {
|
| ... | ... | @@ -189,6 +189,10 @@ mozilla::ipc::IPCResult CanvasTranslator::RecvInitTranslator( |
| 189 | 189 | }
|
| 190 | 190 | |
| 191 | 191 | // Use the first buffer as our current buffer.
|
| 192 | + if (aBufferHandles.IsEmpty()) {
|
|
| 193 | + Deactivate();
|
|
| 194 | + return IPC_FAIL(this, "No canvas buffer shared memory supplied.");
|
|
| 195 | + }
|
|
| 192 | 196 | mDefaultBufferSize = aBufferSize;
|
| 193 | 197 | auto handleIter = aBufferHandles.begin();
|
| 194 | 198 | if (!CreateAndMapShmem(mCurrentShmem.shmem, std::move(*handleIter),
|
| ... | ... | @@ -365,11 +369,19 @@ void CanvasTranslator::GetDataSurface(uint64_t aSurfaceRef) { |
| 365 | 369 | }
|
| 366 | 370 | |
| 367 | 371 | void CanvasTranslator::RecycleBuffer() {
|
| 372 | + if (!mCurrentShmem.IsValid()) {
|
|
| 373 | + return;
|
|
| 374 | + }
|
|
| 375 | + |
|
| 368 | 376 | mCanvasShmems.emplace(std::move(mCurrentShmem));
|
| 369 | 377 | NextBuffer();
|
| 370 | 378 | }
|
| 371 | 379 | |
| 372 | 380 | void CanvasTranslator::NextBuffer() {
|
| 381 | + if (mCanvasShmems.empty()) {
|
|
| 382 | + return;
|
|
| 383 | + }
|
|
| 384 | + |
|
| 373 | 385 | // Check and signal the writer when we finish with a buffer, because it
|
| 374 | 386 | // might have hit the buffer count limit and be waiting to use our old one.
|
| 375 | 387 | CheckAndSignalWriter();
|
| ... | ... | @@ -1518,7 +1518,7 @@ void Statistics::recordParallelPhase(PhaseKind phaseKind, |
| 1518 | 1518 | TimeDuration duration) {
|
| 1519 | 1519 | MOZ_ASSERT(CurrentThreadCanAccessRuntime(gc->rt));
|
| 1520 | 1520 | |
| 1521 | - if (aborted) {
|
|
| 1521 | + if (slices_.empty()) {
|
|
| 1522 | 1522 | return;
|
| 1523 | 1523 | }
|
| 1524 | 1524 |
| ... | ... | @@ -85,7 +85,11 @@ class PrintTranslator final : public Translator { |
| 85 | 85 | }
|
| 86 | 86 | |
| 87 | 87 | void AddDrawTarget(ReferencePtr aRefPtr, DrawTarget* aDT) final {
|
| 88 | - mDrawTargets.InsertOrUpdate(aRefPtr, RefPtr{aDT});
|
|
| 88 | + RefPtr<DrawTarget>& value = mDrawTargets.LookupOrInsert(aRefPtr);
|
|
| 89 | + if (mCurrentDT && mCurrentDT == value) {
|
|
| 90 | + mCurrentDT = nullptr;
|
|
| 91 | + }
|
|
| 92 | + value = aDT;
|
|
| 89 | 93 | }
|
| 90 | 94 | |
| 91 | 95 | void AddPath(ReferencePtr aRefPtr, Path* aPath) final {
|
| ... | ... | @@ -119,11 +123,11 @@ class PrintTranslator final : public Translator { |
| 119 | 123 | }
|
| 120 | 124 | |
| 121 | 125 | void RemoveDrawTarget(ReferencePtr aRefPtr) final {
|
| 122 | - ReferencePtr currentDT = mCurrentDT;
|
|
| 123 | - if (currentDT == aRefPtr) {
|
|
| 126 | + RefPtr<DrawTarget> removedDT;
|
|
| 127 | + if (mDrawTargets.Remove(aRefPtr, getter_AddRefs(removedDT)) &&
|
|
| 128 | + mCurrentDT == removedDT) {
|
|
| 124 | 129 | mCurrentDT = nullptr;
|
| 125 | 130 | }
|
| 126 | - mDrawTargets.Remove(aRefPtr);
|
|
| 127 | 131 | }
|
| 128 | 132 | |
| 129 | 133 | bool SetCurrentDrawTarget(ReferencePtr aRefPtr) final {
|
| ... | ... | @@ -72,7 +72,7 @@ public class IntentUtils { |
| 72 | 72 | }
|
| 73 | 73 | |
| 74 | 74 | if (("intent".equals(scheme) || "android-app".equals(scheme))) {
|
| 75 | - // Bug 1356893 - Rject intents with file data schemes.
|
|
| 75 | + // Bug 1356893 - Reject intents with file data schemes.
|
|
| 76 | 76 | return getSafeIntent(aUri) != null;
|
| 77 | 77 | }
|
| 78 | 78 | |
| ... | ... | @@ -98,8 +98,11 @@ public class IntentUtils { |
| 98 | 98 | }
|
| 99 | 99 | |
| 100 | 100 | final Uri data = intent.getData();
|
| 101 | - if (data != null && "file".equals(normalizeUriScheme(data).getScheme())) {
|
|
| 102 | - return null;
|
|
| 101 | + if (data != null) {
|
|
| 102 | + final String scheme = normalizeUriScheme(data).getScheme();
|
|
| 103 | + if ("file".equals(scheme) || "fido".equals(scheme)) {
|
|
| 104 | + return null;
|
|
| 105 | + }
|
|
| 103 | 106 | }
|
| 104 | 107 | |
| 105 | 108 | // Only open applications which can accept arbitrary data from a browser.
|
| ... | ... | @@ -1953,6 +1953,14 @@ |
| 1953 | 1953 | value: false
|
| 1954 | 1954 | mirror: always
|
| 1955 | 1955 | |
| 1956 | +# If true, we'll use the triggering principal rather than the loading principal
|
|
| 1957 | +# when doing CORS checks. This might be needed for WebExtensions to load their
|
|
| 1958 | +# own resources from content that they inject into sites.
|
|
| 1959 | +- name: content.cors.use_triggering_principal
|
|
| 1960 | + type: bool
|
|
| 1961 | + value: false
|
|
| 1962 | + mirror: always
|
|
| 1963 | + |
|
| 1956 | 1964 | # Back off timer notification after count.
|
| 1957 | 1965 | # -1 means never.
|
| 1958 | 1966 | - name: content.notify.backoffcount
|
| ... | ... | @@ -304,6 +304,8 @@ void SandboxLaunch::Configure(GeckoProcessType aType, SandboxingKind aKind, |
| 304 | 304 | return;
|
| 305 | 305 | }
|
| 306 | 306 | |
| 307 | + // Warning: don't combine multiple case labels, even if the code is
|
|
| 308 | + // currently the same, to avoid mistakes when changes are made.
|
|
| 307 | 309 | switch (aType) {
|
| 308 | 310 | case GeckoProcessType_Socket:
|
| 309 | 311 | if (level >= 1) {
|
| ... | ... | @@ -312,6 +314,12 @@ void SandboxLaunch::Configure(GeckoProcessType aType, SandboxingKind aKind, |
| 312 | 314 | }
|
| 313 | 315 | break;
|
| 314 | 316 | case GeckoProcessType_GMPlugin:
|
| 317 | + if (level >= 1) {
|
|
| 318 | + canChroot = true;
|
|
| 319 | + flags |= CLONE_NEWIPC;
|
|
| 320 | + flags |= CLONE_NEWNET;
|
|
| 321 | + }
|
|
| 322 | + break;
|
|
| 315 | 323 | case GeckoProcessType_RDD:
|
| 316 | 324 | if (level >= 1) {
|
| 317 | 325 | canChroot = true;
|