lists.torproject.org
Sign In Sign Up
Manage this list Sign In Sign Up

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

tbb-commits

Thread Start a new thread
Download
Threads by month
  • ----- 2025 -----
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2022 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2021 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2020 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2019 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2018 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2017 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2016 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2015 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2014 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
tbb-commits@lists.torproject.org

May 2024

  • 1 participants
  • 147 discussions
[Git][tpo/applications/firefox-android][firefox-android-115.2.1-13.5-1] Bug 42652: Pass the list of supported languages to GeckoView.
by Pier Angelo Vendrame (@pierov) 09 May '24

09 May '24
Pier Angelo Vendrame pushed to branch firefox-android-115.2.1-13.5-1 at The Tor Project / Applications / firefox-android Commits: c11e7b38 by Pier Angelo Vendrame at 2024-05-09T18:06:03+02:00 Bug 42652: Pass the list of supported languages to GeckoView. It will be used to prevent leaks about regional preferences. - - - - - 1 changed file: - fenix/app/src/main/java/org/mozilla/fenix/gecko/GeckoProvider.kt Changes: ===================================== fenix/app/src/main/java/org/mozilla/fenix/gecko/GeckoProvider.kt ===================================== @@ -14,6 +14,7 @@ import mozilla.components.concept.storage.LoginsStorage import mozilla.components.lib.crash.handler.CrashHandlerService import mozilla.components.service.sync.autofill.GeckoCreditCardsAddressesStorageDelegate import mozilla.components.service.sync.logins.GeckoLoginStorageDelegate +import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.Config import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.settings @@ -58,6 +59,7 @@ object GeckoProvider { .contentBlocking(policy.toContentBlockingSetting()) .debugLogging(Config.channel.isDebug || context.components.settings.enableGeckoLogs) .aboutConfigEnabled(Config.channel.isBeta || Config.channel.isNightlyOrDebug) + .supportedLocales(BuildConfig.SUPPORTED_LOCALE_ARRAY.toList()) .build() val settings = context.components.settings View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/commit/c11… -- This project does not include diff previews in email notifications. View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/commit/c11… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][tor-browser-115.11.0esr-13.5-1] 2 commits: fixup! Bug 40199: Avoid using system locale for intl.accept_languages in GeckoView
by Pier Angelo Vendrame (@pierov) 09 May '24

09 May '24
Pier Angelo Vendrame pushed to branch tor-browser-115.11.0esr-13.5-1 at The Tor Project / Applications / Tor Browser Commits: 83a3762f by Pier Angelo Vendrame at 2024-05-09T18:04:04+02:00 fixup! Bug 40199: Avoid using system locale for intl.accept_languages in GeckoView Revert &quot;Bug 40199: Avoid using system locale for intl.accept_languages in GeckoView&quot; This reverts commit ff97b6fb06850784785e6993c256bef315b2525f. - - - - - e6f7f151 by Pier Angelo Vendrame at 2024-05-09T18:04:07+02:00 Bug 42562: Normalized the Accepted Languages on Android. The OS language might be outside the list of actually supported languages and it might leak the user&#39;s region. Therefore, we force the locale reported in Accept-Language to match one we support with translations, even when it means using a not exact region tag. - - - - - 1 changed file: - mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java Changes: ===================================== mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java ===================================== @@ -22,7 +22,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; import java.util.Locale; import org.mozilla.gecko.EventDispatcher; import org.mozilla.gecko.GeckoSystemStateListener; @@ -455,6 +456,16 @@ public final class GeckoRuntimeSettings extends RuntimeSettings { return this; } + public @NonNull Builder supportedLocales(final Collection<String> locales) { + getSettings().mSupportedLocales.clear(); + for (String tag : locales) { + Locale locale = Locale.forLanguageTag(tag); + getSettings().mSupportedLocales.put(locale, locale); + getSettings().mSupportedLocales.put(new Locale(locale.getLanguage()), locale); + } + return this; + } + /** * Sets whether we should spoof locale to English for webpages. * @@ -546,6 +557,7 @@ public final class GeckoRuntimeSettings extends RuntimeSettings { /* package */ int mScreenHeightOverride; /* package */ Class<? extends Service> mCrashHandler; /* package */ String[] mRequestedLocales; + /* package */ HashMap<Locale, Locale> mSupportedLocales = new HashMap<>(); /* package */ RuntimeTelemetry.Proxy mTelemetryProxy; /** @@ -602,6 +614,7 @@ public final class GeckoRuntimeSettings extends RuntimeSettings { mRequestedLocales = settings.mRequestedLocales; mConfigFilePath = settings.mConfigFilePath; mTelemetryProxy = settings.mTelemetryProxy; + mSupportedLocales = settings.mSupportedLocales; } /* package */ void commit() { @@ -810,30 +823,39 @@ public final class GeckoRuntimeSettings extends RuntimeSettings { EventDispatcher.getInstance().dispatch("GeckoView:SetLocale", data); } + private Locale getLocaleIfSupported(String tag) { + Locale exact = Locale.forLanguageTag(tag); + if (mSupportedLocales.containsKey(exact)) { + return exact; + } + Locale fallback = new Locale(exact.getLanguage()); + return mSupportedLocales.get(fallback); + } + private String computeAcceptLanguages() { - final ArrayList<String> locales = new ArrayList<String>(); - - // In Desktop, these are defined in the `intl.accept_languages` localized property. - // At some point we should probably use the same values here, but for now we use a simple - // strategy which will hopefully result in reasonable acceptLanguage values. - if (mRequestedLocales != null && mRequestedLocales.length > 0) { - String locale = mRequestedLocales[0].toLowerCase(Locale.ROOT); - // No need to include `en-us` twice. - if (!locale.equals("en-us")) { - locales.add(locale); - if (locale.contains("-")) { - String lang = locale.split("-")[0]; - // No need to include `en` twice. - if (!lang.equals("en")) { - locales.add(lang); - } + Locale locale = null; + if (mRequestedLocales != null) { + for (String tag : mRequestedLocales) { + locale = getLocaleIfSupported(tag); + if (locale != null) { + break; } } } - locales.add("en-us"); - locales.add("en"); - - return TextUtils.join(",", locales); + if (locale == null) { + for (final String tag : getDefaultLocales()) { + locale = getLocaleIfSupported(tag); + if (locale != null) { + break; + } + } + } + String acceptLanguages = locale != null ? locale.toString().replace('_', '-') : "en-US"; + if (acceptLanguages.equals("en-US")) { + // For consistency with spoof English. + acceptLanguages += ", en"; + } + return acceptLanguages; } private static String[] getDefaultLocales() { View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/66e2e3… -- This project does not include diff previews in email notifications. View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/66e2e3… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][tor-browser-115.11.0esr-13.0-1] fixup! Bug 30237: Add v3 onion services client authentication prompt
by ma1 (@ma1) 09 May '24

09 May '24
ma1 pushed to branch tor-browser-115.11.0esr-13.0-1 at The Tor Project / Applications / Tor Browser Commits: e4ed3f35 by hackademix at 2024-05-09T17:49:50+02:00 fixup! Bug 30237: Add v3 onion services client authentication prompt Bug 42557: Fix regression in Onion Services authentication prompt focus - - - - - 1 changed file: - browser/components/onionservices/content/authPrompt.js Changes: ===================================== browser/components/onionservices/content/authPrompt.js ===================================== @@ -81,8 +81,18 @@ const OnionAuthPrompt = (function () { ); }, + _autoFocus(event) { + event.target.ownerGlobal.focus(); + }, + _onPromptShowing(aWarningMessage) { let xulDoc = this._browser.ownerDocument; + + // Force back focus: tor-browser#41856 + (this._popupElem = xulDoc.getElementById( + "tor-clientauth-notification" + ))?.addEventListener("click", this._autoFocus); + let descElem = xulDoc.getElementById("tor-clientauth-notification-desc"); if (descElem) { // Handle replacement of the onion name within the localized @@ -153,6 +163,7 @@ const OnionAuthPrompt = (function () { this._boundOnKeyFieldInput = undefined; } } + this._popupElem?.removeEventListener("click", this._autoFocus); }, _onKeyFieldKeyPress(aEvent) { View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/e4ed3f3… -- This project does not include diff previews in email notifications. View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/e4ed3f3… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/firefox-android][firefox-android-115.2.1-13.5-1] 3 commits: Bug 1846306 - Do not throw IllegalStateException when unable to find a session...
by ma1 (@ma1) 09 May '24

09 May '24
ma1 pushed to branch firefox-android-115.2.1-13.5-1 at The Tor Project / Applications / firefox-android Commits: ccabd9ad by Arturo Mejia at 2024-05-09T15:58:16+02:00 Bug 1846306 - Do not throw IllegalStateException when unable to find a session for given prompt request in onContentPermissionRequested - - - - - 40cae60d by hackademix at 2024-05-09T15:58:20+02:00 Bug 1871217: Improve permission handling in Fullscreen - BP, tor-browser#42656 - - - - - 46475c73 by hackademix at 2024-05-09T15:58:20+02:00 Bug 1892296 - improve webauthn experience - BP, tor-browser#42656 - - - - - 5 changed files: - android-components/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsFeature.kt - android-components/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsFeatureTest.kt - android-components/components/feature/webauthn/src/main/java/mozilla/components/feature/webauthn/WebAuthnFeature.kt - android-components/components/feature/webauthn/src/test/java/mozilla/components/feature/webauthn/WebAuthnFeatureTest.kt - fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt Changes: ===================================== android-components/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsFeature.kt ===================================== @@ -56,12 +56,14 @@ import mozilla.components.concept.engine.permission.SitePermissions import mozilla.components.concept.engine.permission.SitePermissions.Status.ALLOWED import mozilla.components.concept.engine.permission.SitePermissions.Status.BLOCKED import mozilla.components.concept.engine.permission.SitePermissionsStorage +import mozilla.components.feature.session.SessionUseCases import mozilla.components.feature.sitepermissions.SitePermissionsFeature.DialogConfig import mozilla.components.feature.tabs.TabsUseCases.SelectOrAddUseCase import mozilla.components.lib.state.ext.flowScoped import mozilla.components.support.base.feature.LifecycleAwareFeature import mozilla.components.support.base.feature.OnNeedToRequestPermissions import mozilla.components.support.base.feature.PermissionsFeature +import mozilla.components.support.base.log.logger.Logger import mozilla.components.support.ktx.android.content.isPermissionGranted import mozilla.components.support.ktx.kotlin.getOrigin import mozilla.components.support.ktx.kotlin.stripDefaultPort @@ -72,8 +74,6 @@ import mozilla.components.ui.icons.R as iconsR internal const val PROMPT_FRAGMENT_TAG = "mozac_feature_sitepermissions_prompt_dialog" -private const val FULL_SCREEN_NOTIFICATION_TAG = "mozac_feature_prompts_full_screen_notification_dialog" - @VisibleForTesting internal const val STORAGE_ACCESS_DOCUMENTATION_URL = "https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API" @@ -94,13 +94,15 @@ internal const val STORAGE_ACCESS_DOCUMENTATION_URL = * need to be requested. Once the request is completed, [onPermissionsResult] needs to be invoked. * @property onShouldShowRequestPermissionRationale a callback that allows the feature to query * the ActivityCompat.shouldShowRequestPermissionRationale or the Fragment.shouldShowRequestPermissionRationale values. + * @property exitFullscreenUseCase optional the use case in charge of exiting fullscreen * @property shouldShowDoNotAskAgainCheckBox optional Visibility for Do not ask again Checkbox **/ @Suppress("TooManyFunctions", "LargeClass", "LongParameterList") class SitePermissionsFeature( private val context: Context, - private var sessionId: String? = null, + @set:VisibleForTesting + internal var sessionId: String? = null, private val storage: SitePermissionsStorage = OnDiskSitePermissionsStorage(context), var sitePermissionsRules: SitePermissionsRules? = null, private val fragmentManager: FragmentManager, @@ -109,6 +111,7 @@ class SitePermissionsFeature( override val onNeedToRequestPermissions: OnNeedToRequestPermissions, val onShouldShowRequestPermissionRationale: (permission: String) -> Boolean, private val store: BrowserStore, + private val exitFullscreenUseCase: SessionUseCases.ExitFullScreenUseCase = SessionUseCases(store).exitFullscreen, private val shouldShowDoNotAskAgainCheckBox: Boolean = true, ) : LifecycleAwareFeature, PermissionsFeature { @VisibleForTesting @@ -116,6 +119,8 @@ class SitePermissionsFeature( SelectOrAddUseCase(store) } + private val logger = Logger("SitePermissionsFeature") + internal val ioCoroutineScope by lazy { coroutineScopeInitializer() } internal var coroutineScopeInitializer = { @@ -428,26 +433,29 @@ class SitePermissionsFeature( consumePermissionRequest(permissionRequest) return null } - - val private: Boolean = store.state.findTabOrCustomTabOrSelectedTab(sessionId)?.content?.private - ?: throw IllegalStateException("Unable to find session for $sessionId or selected session") + val tab = store.state.findTabOrCustomTabOrSelectedTab(sessionId) + if (tab == null) { + logger.error("Unable to find a tab for $sessionId rejecting the prompt request") + permissionRequest.reject() + consumePermissionRequest(permissionRequest) + return null + } val permissionFromStorage = withContext(coroutineScope.coroutineContext) { - storage.findSitePermissionsBy(origin, private = private) + storage.findSitePermissionsBy(origin, private = tab.content.private) } - val prompt = if (shouldApplyRules(permissionFromStorage)) { handleRuledFlow(permissionRequest, origin) } else { handleNoRuledFlow(permissionFromStorage, permissionRequest, origin) } - val fullScreenNotificationDisplayed = - fragmentManager.fragments.any { fragment -> fragment.tag == FULL_SCREEN_NOTIFICATION_TAG } - - return if (fullScreenNotificationDisplayed || prompt == null) { + return if (prompt == null) { null } else { + // If we are in fullscreen, then exit to show the permission prompt. + // This won't have any effect if we are not in fullscreen. + exitFullscreenUseCase.invoke(tab.id) prompt.show(fragmentManager, PROMPT_FRAGMENT_TAG) prompt } ===================================== android-components/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsFeatureTest.kt ===================================== @@ -600,6 +600,24 @@ class SitePermissionsFeatureTest { verify(sitePermissionFeature).consumePermissionRequest(mockPermissionRequest) } + @Test + fun `GIVEN sessionId which does not match a selected or custom tab WHEN onContentPermissionRequested() THEN reject, consumePermissionRequest are called `() { + val mockPermissionRequest: PermissionRequest = mock { + whenever(permissions).thenReturn(listOf(ContentVideoCamera(id = "permission"))) + } + + doNothing().`when`(mockPermissionRequest).reject() + + sitePermissionFeature.sessionId = null + + runTestOnMain { + sitePermissionFeature.onContentPermissionRequested(mockPermissionRequest, URL) + } + + verify(mockPermissionRequest).reject() + verify(sitePermissionFeature).consumePermissionRequest(mockPermissionRequest) + } + @Test fun `GIVEN location permissionRequest and shouldApplyRules is true WHEN onContentPermissionRequested() THEN handleRuledFlow is called`() = runTestOnMain { // given ===================================== android-components/components/feature/webauthn/src/main/java/mozilla/components/feature/webauthn/WebAuthnFeature.kt ===================================== @@ -20,6 +20,8 @@ import mozilla.components.support.base.log.logger.Logger class WebAuthnFeature( private val engine: Engine, private val activity: Activity, + private val exitFullScreen: (String?) -> Unit, + private val currentTab: () -> String?, ) : LifecycleAwareFeature, ActivityResultHandler, ActivityDelegate { private val logger = Logger("WebAuthnFeature") private var requestCodeCounter = ACTIVITY_REQUEST_CODE @@ -53,6 +55,7 @@ class WebAuthnFeature( override fun startIntentSenderForResult(intent: IntentSender, onResult: (Intent?) -> Unit) { logger.info("Received activity delegate request with code: $requestCodeCounter") + exitFullScreen(currentTab()) activity.startIntentSenderForResult(intent, requestCodeCounter, null, 0, 0, 0) callbackRef = onResult } ===================================== android-components/components/feature/webauthn/src/test/java/mozilla/components/feature/webauthn/WebAuthnFeatureTest.kt ===================================== @@ -22,6 +22,8 @@ import org.mockito.Mockito.verify class WebAuthnFeatureTest { private lateinit var engine: Engine private lateinit var activity: Activity + private val exitFullScreen: (String?) -> Unit = { _ -> exitFullScreenUseCaseCalled = true } + private var exitFullScreenUseCaseCalled = false @Before fun setup() { @@ -31,7 +33,7 @@ class WebAuthnFeatureTest { @Test fun `feature registers itself on start`() { - val feature = WebAuthnFeature(engine, activity) + val feature = webAuthnFeature() feature.start() @@ -40,7 +42,7 @@ class WebAuthnFeatureTest { @Test fun `feature unregisters itself on stop`() { - val feature = WebAuthnFeature(engine, activity) + val feature = webAuthnFeature() feature.stop() @@ -49,7 +51,7 @@ class WebAuthnFeatureTest { @Test fun `activity delegate starts intent sender`() { - val feature = WebAuthnFeature(engine, activity) + val feature = webAuthnFeature() val callback: ((Intent?) -> Unit) = { } val intentSender: IntentSender = mock() @@ -60,7 +62,7 @@ class WebAuthnFeatureTest { @Test fun `callback is invoked`() { - val feature = WebAuthnFeature(engine, activity) + val feature = webAuthnFeature() var callbackInvoked = false val callback: ((Intent?) -> Unit) = { callbackInvoked = true } val intentSender: IntentSender = mock() @@ -77,10 +79,14 @@ class WebAuthnFeatureTest { @Test fun `feature won't process results with the wrong request code`() { - val feature = WebAuthnFeature(engine, activity) + val feature = webAuthnFeature() val result = feature.onActivityResult(ACTIVITY_REQUEST_CODE - 5, Intent(), 0) assertFalse(result) } + + private fun webAuthnFeature(): WebAuthnFeature { + return WebAuthnFeature(engine, activity, { exitFullScreen("") }) { "" } + } } ===================================== fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt ===================================== @@ -830,6 +830,8 @@ abstract class BaseBrowserFragment : feature = WebAuthnFeature( engine = requireComponents.core.engine, activity = requireActivity(), + exitFullScreen = requireComponents.useCases.sessionUseCases.exitFullscreen::invoke, + currentTab = { store.state.selectedTabId }, ), owner = this, view = view, View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/compare/fe… -- This project does not include diff previews in email notifications. View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/compare/fe… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][base-browser-115.11.0esr-13.5-1] 3 commits: Bug 1871109 - generateHash in Manifest.sys.mjs should use sha256 r=peterv, a=dmeehan
by ma1 (@ma1) 09 May '24

09 May '24
ma1 pushed to branch base-browser-115.11.0esr-13.5-1 at The Tor Project / Applications / Tor Browser Commits: 6d5a0677 by Nuohan Li at 2024-05-09T13:38:19+02:00 Bug 1871109 - generateHash in Manifest.sys.mjs should use sha256 r=peterv, a=dmeehan Differential Revision: https://phabricator.services.mozilla.com/D204928 - - - - - 58dc31a0 by Jonathan Kew at 2024-05-09T13:38:20+02:00 Bug 1890204 - Ensure font entry&#39;s unitsPerEm and font extents are initialized when gfxFont is created. r=gfx-reviewers,lsalzman This means that by the time we potentially call GetFontExtents() when drawing, the extents fields are guaranteed to have been been initialized, and there&#39;s no risk of the (read-only) access here racing with setting them in UnitsPerEm(). Differential Revision: https://phabricator.services.mozilla.com/D206920 - - - - - e7430547 by Jonathan Kew at 2024-05-09T13:38:21+02:00 Bug 1893891 - Clear mSharedBlobData if blob creation failed. a=dmeehan Original Revision: https://phabricator.services.mozilla.com/D208983 Differential Revision: https://phabricator.services.mozilla.com/D209209 - - - - - 5 changed files: - dom/manifest/Manifest.sys.mjs - dom/manifest/test/browser_Manifest_install.js - gfx/thebes/gfxFont.cpp - gfx/thebes/gfxFontEntry.cpp - gfx/thebes/gfxFontEntry.h Changes: ===================================== dom/manifest/Manifest.sys.mjs ===================================== @@ -29,11 +29,11 @@ ChromeUtils.defineESModuleGetters(lazy, { * @note The generated hash is returned in base64 form. Mind the fact base64 * is case-sensitive if you are going to reuse this code. */ -function generateHash(aString) { +function generateHash(aString, hashAlg) { const cryptoHash = Cc["@mozilla.org/security/hash;1"].createInstance( Ci.nsICryptoHash ); - cryptoHash.init(Ci.nsICryptoHash.MD5); + cryptoHash.init(hashAlg); const stringStream = Cc[ "@mozilla.org/io/string-input-stream;1" ].createInstance(Ci.nsIStringInputStream); @@ -66,11 +66,39 @@ class Manifest { this._manifestUrl = manifestUrl; // The key for this is the manifests URL that is required to be unique. // However arbitrary urls are not safe file paths so lets hash it. - const fileName = generateHash(manifestUrl) + ".json"; - this._path = PathUtils.join(MANIFESTS_DIR, fileName); + const filename = + generateHash(manifestUrl, Ci.nsICryptoHash.SHA256) + ".json"; + this._path = PathUtils.join(MANIFESTS_DIR, filename); this.browser = browser; } + /** + * See Bug 1871109 + * This function is called at the beginning of initialize() to check if a given + * manifest has MD5 based filename, if so we remove it and migrate the content to + * a new file with SHA256 based name. + * This is done due to security concern, as MD5 is an outdated hashing algorithm and + * shouldn't be used anymore + */ + async removeMD5BasedFilename() { + const filenameMD5 = + generateHash(this._manifestUrl, Ci.nsICryptoHash.MD5) + ".json"; + const MD5Path = PathUtils.join(MANIFESTS_DIR, filenameMD5); + try { + await IOUtils.copy(MD5Path, this._path, { noOverwrite: true }); + } catch (error) { + // we are ignoring the failures returned from copy as it should not stop us from + // installing a new manifest + } + + // Remove the old MD5 based file unconditionally to ensure it's no longer used + try { + await IOUtils.remove(MD5Path); + } catch { + // ignore the error in case MD5 based file does not exist + } + } + get browser() { return this._browser; } @@ -80,6 +108,7 @@ class Manifest { } async initialize() { + await this.removeMD5BasedFilename(); this._store = new lazy.JSONFile({ path: this._path, saveDelayMs: 100 }); await this._store.load(); } ===================================== dom/manifest/test/browser_Manifest_install.js ===================================== @@ -23,18 +23,59 @@ function makeTestURL() { return url.href; } +function generateHash(aString, hashAlg) { + const cryptoHash = Cc["@mozilla.org/security/hash;1"].createInstance( + Ci.nsICryptoHash + ); + cryptoHash.init(hashAlg); + const stringStream = Cc[ + "@mozilla.org/io/string-input-stream;1" + ].createInstance(Ci.nsIStringInputStream); + stringStream.data = aString; + cryptoHash.updateFromStream(stringStream, -1); + // base64 allows the '/' char, but we can't use it for filenames. + return cryptoHash.finish(true).replace(/\//g, "-"); +} + +const MANIFESTS_DIR = PathUtils.join(PathUtils.profileDir, "manifests"); + add_task(async function () { const tabOptions = { gBrowser, url: makeTestURL() }; + const filenameMD5 = generateHash(manifestUrl, Ci.nsICryptoHash.MD5) + ".json"; + const filenameSHA = + generateHash(manifestUrl, Ci.nsICryptoHash.SHA256) + ".json"; + const manifestMD5Path = PathUtils.join(MANIFESTS_DIR, filenameMD5); + const manifestSHAPath = PathUtils.join(MANIFESTS_DIR, filenameSHA); + await BrowserTestUtils.withNewTab(tabOptions, async function (browser) { - let manifest = await Manifests.getManifest(browser, manifestUrl); - is(manifest.installed, false, "We haven't installed this manifest yet"); + let tmpManifest = await Manifests.getManifest(browser, manifestUrl); + is(tmpManifest.installed, false, "We haven't installed this manifest yet"); + + await tmpManifest.install(); + // making sure the manifest is actually installed before proceeding + await tmpManifest._store._save(); + await IOUtils.move(tmpManifest.path, manifestMD5Path); + + let exists = await IOUtils.exists(tmpManifest.path); + is( + exists, + false, + "Manually moved manifest from SHA256 based path to MD5 based path" + ); + Manifests.manifestObjs.delete(manifestUrl); + + let manifest = await Manifests.getManifest(browser, manifestUrl); await manifest.install(browser); is(manifest.name, "hello World", "Manifest has correct name"); is(manifest.installed, true, "Manifest is installed"); is(manifest.url, manifestUrl, "has correct url"); is(manifest.browser, browser, "has correct browser"); + is(manifest.path, manifestSHAPath, "has correct path"); + + exists = await IOUtils.exists(manifestMD5Path); + is(exists, false, "MD5 based manifest removed"); manifest = await Manifests.getManifest(browser, manifestUrl); is(manifest.installed, true, "New instances are installed"); ===================================== gfx/thebes/gfxFont.cpp ===================================== @@ -952,6 +952,10 @@ gfxFont::gfxFont(const RefPtr<UnscaledFont>& aUnscaledFont, } mKerningSet = HasFeatureSet(HB_TAG('k', 'e', 'r', 'n'), mKerningEnabled); + + // Ensure the gfxFontEntry's unitsPerEm and extents fields are initialized, + // so that GetFontExtents can use them without risk of races. + Unused << mFontEntry->UnitsPerEm(); } gfxFont::~gfxFont() { ===================================== gfx/thebes/gfxFontEntry.cpp ===================================== @@ -262,14 +262,22 @@ already_AddRefed<gfxFont> gfxFontEntry::FindOrMakeFont( } uint16_t gfxFontEntry::UnitsPerEm() { + { + AutoReadLock lock(mLock); + if (mUnitsPerEm) { + return mUnitsPerEm; + } + } + + AutoTable headTable(this, TRUETYPE_TAG('h', 'e', 'a', 'd')); + AutoWriteLock lock(mLock); + if (!mUnitsPerEm) { - AutoTable headTable(this, TRUETYPE_TAG('h', 'e', 'a', 'd')); if (headTable) { uint32_t len; const HeadTable* head = reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable, &len)); if (len >= sizeof(HeadTable)) { - mUnitsPerEm = head->unitsPerEm; if (int16_t(head->xMax) > int16_t(head->xMin) && int16_t(head->yMax) > int16_t(head->yMin)) { mXMin = head->xMin; @@ -277,6 +285,7 @@ uint16_t gfxFontEntry::UnitsPerEm() { mXMax = head->xMax; mYMax = head->yMax; } + mUnitsPerEm = head->unitsPerEm; } } @@ -286,12 +295,13 @@ uint16_t gfxFontEntry::UnitsPerEm() { mUnitsPerEm = kInvalidUPEM; } } + return mUnitsPerEm; } bool gfxFontEntry::HasSVGGlyph(uint32_t aGlyphId) { - NS_ASSERTION(mSVGInitialized, - "SVG data has not yet been loaded. TryGetSVGData() first."); + MOZ_ASSERT(mSVGInitialized, + "SVG data has not yet been loaded. TryGetSVGData() first."); return GetSVGGlyphs()->HasSVGGlyph(aGlyphId); } @@ -309,8 +319,8 @@ bool gfxFontEntry::GetSVGGlyphExtents(DrawTarget* aDrawTarget, void gfxFontEntry::RenderSVGGlyph(gfxContext* aContext, uint32_t aGlyphId, SVGContextPaint* aContextPaint) { - NS_ASSERTION(mSVGInitialized, - "SVG data has not yet been loaded. TryGetSVGData() first."); + MOZ_ASSERT(mSVGInitialized, + "SVG data has not yet been loaded. TryGetSVGData() first."); GetSVGGlyphs()->RenderGlyph(aContext, aGlyphId, aContextPaint); } @@ -467,8 +477,9 @@ hb_blob_t* gfxFontEntry::FontTableHashEntry::ShareTableAndGetBlob( HB_MEMORY_MODE_READONLY, mSharedBlobData, DeleteFontTableBlobData); if (mBlob == hb_blob_get_empty()) { // The FontTableBlobData was destroyed during hb_blob_create(). - // The (empty) blob is still be held in the hashtable with a strong + // The (empty) blob will still be held in the hashtable with a strong // reference. + mSharedBlobData = nullptr; return hb_blob_reference(mBlob); } ===================================== gfx/thebes/gfxFontEntry.h ===================================== @@ -538,6 +538,9 @@ class gfxFontEntry { mozilla::gfx::Rect GetFontExtents(float aFUnitScaleFactor) const { // Flip the y-axis here to match the orientation of Gecko's coordinates. + // We don't need to take a lock here because the min/max fields are inert + // after initialization, and we make sure to initialize them at gfxFont- + // creation time. return mozilla::gfx::Rect(float(mXMin) * aFUnitScaleFactor, float(-mYMax) * aFUnitScaleFactor, float(mXMax - mXMin) * aFUnitScaleFactor, View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/98625d… -- This project does not include diff previews in email notifications. View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/98625d… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][tor-browser-115.11.0esr-13.5-1] 3 commits: Bug 1871109 - generateHash in Manifest.sys.mjs should use sha256 r=peterv, a=dmeehan
by ma1 (@ma1) 09 May '24

09 May '24
ma1 pushed to branch tor-browser-115.11.0esr-13.5-1 at The Tor Project / Applications / Tor Browser Commits: 62619558 by Nuohan Li at 2024-05-09T13:37:32+02:00 Bug 1871109 - generateHash in Manifest.sys.mjs should use sha256 r=peterv, a=dmeehan Differential Revision: https://phabricator.services.mozilla.com/D204928 - - - - - 4846c1da by Jonathan Kew at 2024-05-09T13:37:33+02:00 Bug 1890204 - Ensure font entry&#39;s unitsPerEm and font extents are initialized when gfxFont is created. r=gfx-reviewers,lsalzman This means that by the time we potentially call GetFontExtents() when drawing, the extents fields are guaranteed to have been been initialized, and there&#39;s no risk of the (read-only) access here racing with setting them in UnitsPerEm(). Differential Revision: https://phabricator.services.mozilla.com/D206920 - - - - - 66e2e3ef by Jonathan Kew at 2024-05-09T13:37:34+02:00 Bug 1893891 - Clear mSharedBlobData if blob creation failed. a=dmeehan Original Revision: https://phabricator.services.mozilla.com/D208983 Differential Revision: https://phabricator.services.mozilla.com/D209209 - - - - - 5 changed files: - dom/manifest/Manifest.sys.mjs - dom/manifest/test/browser_Manifest_install.js - gfx/thebes/gfxFont.cpp - gfx/thebes/gfxFontEntry.cpp - gfx/thebes/gfxFontEntry.h Changes: ===================================== dom/manifest/Manifest.sys.mjs ===================================== @@ -29,11 +29,11 @@ ChromeUtils.defineESModuleGetters(lazy, { * @note The generated hash is returned in base64 form. Mind the fact base64 * is case-sensitive if you are going to reuse this code. */ -function generateHash(aString) { +function generateHash(aString, hashAlg) { const cryptoHash = Cc["@mozilla.org/security/hash;1"].createInstance( Ci.nsICryptoHash ); - cryptoHash.init(Ci.nsICryptoHash.MD5); + cryptoHash.init(hashAlg); const stringStream = Cc[ "@mozilla.org/io/string-input-stream;1" ].createInstance(Ci.nsIStringInputStream); @@ -66,11 +66,39 @@ class Manifest { this._manifestUrl = manifestUrl; // The key for this is the manifests URL that is required to be unique. // However arbitrary urls are not safe file paths so lets hash it. - const fileName = generateHash(manifestUrl) + ".json"; - this._path = PathUtils.join(MANIFESTS_DIR, fileName); + const filename = + generateHash(manifestUrl, Ci.nsICryptoHash.SHA256) + ".json"; + this._path = PathUtils.join(MANIFESTS_DIR, filename); this.browser = browser; } + /** + * See Bug 1871109 + * This function is called at the beginning of initialize() to check if a given + * manifest has MD5 based filename, if so we remove it and migrate the content to + * a new file with SHA256 based name. + * This is done due to security concern, as MD5 is an outdated hashing algorithm and + * shouldn't be used anymore + */ + async removeMD5BasedFilename() { + const filenameMD5 = + generateHash(this._manifestUrl, Ci.nsICryptoHash.MD5) + ".json"; + const MD5Path = PathUtils.join(MANIFESTS_DIR, filenameMD5); + try { + await IOUtils.copy(MD5Path, this._path, { noOverwrite: true }); + } catch (error) { + // we are ignoring the failures returned from copy as it should not stop us from + // installing a new manifest + } + + // Remove the old MD5 based file unconditionally to ensure it's no longer used + try { + await IOUtils.remove(MD5Path); + } catch { + // ignore the error in case MD5 based file does not exist + } + } + get browser() { return this._browser; } @@ -80,6 +108,7 @@ class Manifest { } async initialize() { + await this.removeMD5BasedFilename(); this._store = new lazy.JSONFile({ path: this._path, saveDelayMs: 100 }); await this._store.load(); } ===================================== dom/manifest/test/browser_Manifest_install.js ===================================== @@ -23,18 +23,59 @@ function makeTestURL() { return url.href; } +function generateHash(aString, hashAlg) { + const cryptoHash = Cc["@mozilla.org/security/hash;1"].createInstance( + Ci.nsICryptoHash + ); + cryptoHash.init(hashAlg); + const stringStream = Cc[ + "@mozilla.org/io/string-input-stream;1" + ].createInstance(Ci.nsIStringInputStream); + stringStream.data = aString; + cryptoHash.updateFromStream(stringStream, -1); + // base64 allows the '/' char, but we can't use it for filenames. + return cryptoHash.finish(true).replace(/\//g, "-"); +} + +const MANIFESTS_DIR = PathUtils.join(PathUtils.profileDir, "manifests"); + add_task(async function () { const tabOptions = { gBrowser, url: makeTestURL() }; + const filenameMD5 = generateHash(manifestUrl, Ci.nsICryptoHash.MD5) + ".json"; + const filenameSHA = + generateHash(manifestUrl, Ci.nsICryptoHash.SHA256) + ".json"; + const manifestMD5Path = PathUtils.join(MANIFESTS_DIR, filenameMD5); + const manifestSHAPath = PathUtils.join(MANIFESTS_DIR, filenameSHA); + await BrowserTestUtils.withNewTab(tabOptions, async function (browser) { - let manifest = await Manifests.getManifest(browser, manifestUrl); - is(manifest.installed, false, "We haven't installed this manifest yet"); + let tmpManifest = await Manifests.getManifest(browser, manifestUrl); + is(tmpManifest.installed, false, "We haven't installed this manifest yet"); + + await tmpManifest.install(); + // making sure the manifest is actually installed before proceeding + await tmpManifest._store._save(); + await IOUtils.move(tmpManifest.path, manifestMD5Path); + + let exists = await IOUtils.exists(tmpManifest.path); + is( + exists, + false, + "Manually moved manifest from SHA256 based path to MD5 based path" + ); + Manifests.manifestObjs.delete(manifestUrl); + + let manifest = await Manifests.getManifest(browser, manifestUrl); await manifest.install(browser); is(manifest.name, "hello World", "Manifest has correct name"); is(manifest.installed, true, "Manifest is installed"); is(manifest.url, manifestUrl, "has correct url"); is(manifest.browser, browser, "has correct browser"); + is(manifest.path, manifestSHAPath, "has correct path"); + + exists = await IOUtils.exists(manifestMD5Path); + is(exists, false, "MD5 based manifest removed"); manifest = await Manifests.getManifest(browser, manifestUrl); is(manifest.installed, true, "New instances are installed"); ===================================== gfx/thebes/gfxFont.cpp ===================================== @@ -952,6 +952,10 @@ gfxFont::gfxFont(const RefPtr<UnscaledFont>& aUnscaledFont, } mKerningSet = HasFeatureSet(HB_TAG('k', 'e', 'r', 'n'), mKerningEnabled); + + // Ensure the gfxFontEntry's unitsPerEm and extents fields are initialized, + // so that GetFontExtents can use them without risk of races. + Unused << mFontEntry->UnitsPerEm(); } gfxFont::~gfxFont() { ===================================== gfx/thebes/gfxFontEntry.cpp ===================================== @@ -262,14 +262,22 @@ already_AddRefed<gfxFont> gfxFontEntry::FindOrMakeFont( } uint16_t gfxFontEntry::UnitsPerEm() { + { + AutoReadLock lock(mLock); + if (mUnitsPerEm) { + return mUnitsPerEm; + } + } + + AutoTable headTable(this, TRUETYPE_TAG('h', 'e', 'a', 'd')); + AutoWriteLock lock(mLock); + if (!mUnitsPerEm) { - AutoTable headTable(this, TRUETYPE_TAG('h', 'e', 'a', 'd')); if (headTable) { uint32_t len; const HeadTable* head = reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable, &len)); if (len >= sizeof(HeadTable)) { - mUnitsPerEm = head->unitsPerEm; if (int16_t(head->xMax) > int16_t(head->xMin) && int16_t(head->yMax) > int16_t(head->yMin)) { mXMin = head->xMin; @@ -277,6 +285,7 @@ uint16_t gfxFontEntry::UnitsPerEm() { mXMax = head->xMax; mYMax = head->yMax; } + mUnitsPerEm = head->unitsPerEm; } } @@ -286,12 +295,13 @@ uint16_t gfxFontEntry::UnitsPerEm() { mUnitsPerEm = kInvalidUPEM; } } + return mUnitsPerEm; } bool gfxFontEntry::HasSVGGlyph(uint32_t aGlyphId) { - NS_ASSERTION(mSVGInitialized, - "SVG data has not yet been loaded. TryGetSVGData() first."); + MOZ_ASSERT(mSVGInitialized, + "SVG data has not yet been loaded. TryGetSVGData() first."); return GetSVGGlyphs()->HasSVGGlyph(aGlyphId); } @@ -309,8 +319,8 @@ bool gfxFontEntry::GetSVGGlyphExtents(DrawTarget* aDrawTarget, void gfxFontEntry::RenderSVGGlyph(gfxContext* aContext, uint32_t aGlyphId, SVGContextPaint* aContextPaint) { - NS_ASSERTION(mSVGInitialized, - "SVG data has not yet been loaded. TryGetSVGData() first."); + MOZ_ASSERT(mSVGInitialized, + "SVG data has not yet been loaded. TryGetSVGData() first."); GetSVGGlyphs()->RenderGlyph(aContext, aGlyphId, aContextPaint); } @@ -467,8 +477,9 @@ hb_blob_t* gfxFontEntry::FontTableHashEntry::ShareTableAndGetBlob( HB_MEMORY_MODE_READONLY, mSharedBlobData, DeleteFontTableBlobData); if (mBlob == hb_blob_get_empty()) { // The FontTableBlobData was destroyed during hb_blob_create(). - // The (empty) blob is still be held in the hashtable with a strong + // The (empty) blob will still be held in the hashtable with a strong // reference. + mSharedBlobData = nullptr; return hb_blob_reference(mBlob); } ===================================== gfx/thebes/gfxFontEntry.h ===================================== @@ -538,6 +538,9 @@ class gfxFontEntry { mozilla::gfx::Rect GetFontExtents(float aFUnitScaleFactor) const { // Flip the y-axis here to match the orientation of Gecko's coordinates. + // We don't need to take a lock here because the min/max fields are inert + // after initialization, and we make sure to initialize them at gfxFont- + // creation time. return mozilla::gfx::Rect(float(mXMin) * aFUnitScaleFactor, float(-mYMax) * aFUnitScaleFactor, float(mXMax - mXMin) * aFUnitScaleFactor, View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/410bb2… -- This project does not include diff previews in email notifications. View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/410bb2… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/mullvad-browser][mullvad-browser-115.11.0esr-13.5-1] 3 commits: Bug 1871109 - generateHash in Manifest.sys.mjs should use sha256 r=peterv, a=dmeehan
by ma1 (@ma1) 09 May '24

09 May '24
ma1 pushed to branch mullvad-browser-115.11.0esr-13.5-1 at The Tor Project / Applications / Mullvad Browser Commits: ac1e73ce by Nuohan Li at 2024-05-09T13:36:35+02:00 Bug 1871109 - generateHash in Manifest.sys.mjs should use sha256 r=peterv, a=dmeehan Differential Revision: https://phabricator.services.mozilla.com/D204928 - - - - - f0b17745 by Jonathan Kew at 2024-05-09T13:36:36+02:00 Bug 1890204 - Ensure font entry&#39;s unitsPerEm and font extents are initialized when gfxFont is created. r=gfx-reviewers,lsalzman This means that by the time we potentially call GetFontExtents() when drawing, the extents fields are guaranteed to have been been initialized, and there&#39;s no risk of the (read-only) access here racing with setting them in UnitsPerEm(). Differential Revision: https://phabricator.services.mozilla.com/D206920 - - - - - 29322606 by Jonathan Kew at 2024-05-09T13:36:37+02:00 Bug 1893891 - Clear mSharedBlobData if blob creation failed. a=dmeehan Original Revision: https://phabricator.services.mozilla.com/D208983 Differential Revision: https://phabricator.services.mozilla.com/D209209 - - - - - 5 changed files: - dom/manifest/Manifest.sys.mjs - dom/manifest/test/browser_Manifest_install.js - gfx/thebes/gfxFont.cpp - gfx/thebes/gfxFontEntry.cpp - gfx/thebes/gfxFontEntry.h Changes: ===================================== dom/manifest/Manifest.sys.mjs ===================================== @@ -29,11 +29,11 @@ ChromeUtils.defineESModuleGetters(lazy, { * @note The generated hash is returned in base64 form. Mind the fact base64 * is case-sensitive if you are going to reuse this code. */ -function generateHash(aString) { +function generateHash(aString, hashAlg) { const cryptoHash = Cc["@mozilla.org/security/hash;1"].createInstance( Ci.nsICryptoHash ); - cryptoHash.init(Ci.nsICryptoHash.MD5); + cryptoHash.init(hashAlg); const stringStream = Cc[ "@mozilla.org/io/string-input-stream;1" ].createInstance(Ci.nsIStringInputStream); @@ -66,11 +66,39 @@ class Manifest { this._manifestUrl = manifestUrl; // The key for this is the manifests URL that is required to be unique. // However arbitrary urls are not safe file paths so lets hash it. - const fileName = generateHash(manifestUrl) + ".json"; - this._path = PathUtils.join(MANIFESTS_DIR, fileName); + const filename = + generateHash(manifestUrl, Ci.nsICryptoHash.SHA256) + ".json"; + this._path = PathUtils.join(MANIFESTS_DIR, filename); this.browser = browser; } + /** + * See Bug 1871109 + * This function is called at the beginning of initialize() to check if a given + * manifest has MD5 based filename, if so we remove it and migrate the content to + * a new file with SHA256 based name. + * This is done due to security concern, as MD5 is an outdated hashing algorithm and + * shouldn't be used anymore + */ + async removeMD5BasedFilename() { + const filenameMD5 = + generateHash(this._manifestUrl, Ci.nsICryptoHash.MD5) + ".json"; + const MD5Path = PathUtils.join(MANIFESTS_DIR, filenameMD5); + try { + await IOUtils.copy(MD5Path, this._path, { noOverwrite: true }); + } catch (error) { + // we are ignoring the failures returned from copy as it should not stop us from + // installing a new manifest + } + + // Remove the old MD5 based file unconditionally to ensure it's no longer used + try { + await IOUtils.remove(MD5Path); + } catch { + // ignore the error in case MD5 based file does not exist + } + } + get browser() { return this._browser; } @@ -80,6 +108,7 @@ class Manifest { } async initialize() { + await this.removeMD5BasedFilename(); this._store = new lazy.JSONFile({ path: this._path, saveDelayMs: 100 }); await this._store.load(); } ===================================== dom/manifest/test/browser_Manifest_install.js ===================================== @@ -23,18 +23,59 @@ function makeTestURL() { return url.href; } +function generateHash(aString, hashAlg) { + const cryptoHash = Cc["@mozilla.org/security/hash;1"].createInstance( + Ci.nsICryptoHash + ); + cryptoHash.init(hashAlg); + const stringStream = Cc[ + "@mozilla.org/io/string-input-stream;1" + ].createInstance(Ci.nsIStringInputStream); + stringStream.data = aString; + cryptoHash.updateFromStream(stringStream, -1); + // base64 allows the '/' char, but we can't use it for filenames. + return cryptoHash.finish(true).replace(/\//g, "-"); +} + +const MANIFESTS_DIR = PathUtils.join(PathUtils.profileDir, "manifests"); + add_task(async function () { const tabOptions = { gBrowser, url: makeTestURL() }; + const filenameMD5 = generateHash(manifestUrl, Ci.nsICryptoHash.MD5) + ".json"; + const filenameSHA = + generateHash(manifestUrl, Ci.nsICryptoHash.SHA256) + ".json"; + const manifestMD5Path = PathUtils.join(MANIFESTS_DIR, filenameMD5); + const manifestSHAPath = PathUtils.join(MANIFESTS_DIR, filenameSHA); + await BrowserTestUtils.withNewTab(tabOptions, async function (browser) { - let manifest = await Manifests.getManifest(browser, manifestUrl); - is(manifest.installed, false, "We haven't installed this manifest yet"); + let tmpManifest = await Manifests.getManifest(browser, manifestUrl); + is(tmpManifest.installed, false, "We haven't installed this manifest yet"); + + await tmpManifest.install(); + // making sure the manifest is actually installed before proceeding + await tmpManifest._store._save(); + await IOUtils.move(tmpManifest.path, manifestMD5Path); + + let exists = await IOUtils.exists(tmpManifest.path); + is( + exists, + false, + "Manually moved manifest from SHA256 based path to MD5 based path" + ); + Manifests.manifestObjs.delete(manifestUrl); + + let manifest = await Manifests.getManifest(browser, manifestUrl); await manifest.install(browser); is(manifest.name, "hello World", "Manifest has correct name"); is(manifest.installed, true, "Manifest is installed"); is(manifest.url, manifestUrl, "has correct url"); is(manifest.browser, browser, "has correct browser"); + is(manifest.path, manifestSHAPath, "has correct path"); + + exists = await IOUtils.exists(manifestMD5Path); + is(exists, false, "MD5 based manifest removed"); manifest = await Manifests.getManifest(browser, manifestUrl); is(manifest.installed, true, "New instances are installed"); ===================================== gfx/thebes/gfxFont.cpp ===================================== @@ -952,6 +952,10 @@ gfxFont::gfxFont(const RefPtr<UnscaledFont>& aUnscaledFont, } mKerningSet = HasFeatureSet(HB_TAG('k', 'e', 'r', 'n'), mKerningEnabled); + + // Ensure the gfxFontEntry's unitsPerEm and extents fields are initialized, + // so that GetFontExtents can use them without risk of races. + Unused << mFontEntry->UnitsPerEm(); } gfxFont::~gfxFont() { ===================================== gfx/thebes/gfxFontEntry.cpp ===================================== @@ -262,14 +262,22 @@ already_AddRefed<gfxFont> gfxFontEntry::FindOrMakeFont( } uint16_t gfxFontEntry::UnitsPerEm() { + { + AutoReadLock lock(mLock); + if (mUnitsPerEm) { + return mUnitsPerEm; + } + } + + AutoTable headTable(this, TRUETYPE_TAG('h', 'e', 'a', 'd')); + AutoWriteLock lock(mLock); + if (!mUnitsPerEm) { - AutoTable headTable(this, TRUETYPE_TAG('h', 'e', 'a', 'd')); if (headTable) { uint32_t len; const HeadTable* head = reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable, &len)); if (len >= sizeof(HeadTable)) { - mUnitsPerEm = head->unitsPerEm; if (int16_t(head->xMax) > int16_t(head->xMin) && int16_t(head->yMax) > int16_t(head->yMin)) { mXMin = head->xMin; @@ -277,6 +285,7 @@ uint16_t gfxFontEntry::UnitsPerEm() { mXMax = head->xMax; mYMax = head->yMax; } + mUnitsPerEm = head->unitsPerEm; } } @@ -286,12 +295,13 @@ uint16_t gfxFontEntry::UnitsPerEm() { mUnitsPerEm = kInvalidUPEM; } } + return mUnitsPerEm; } bool gfxFontEntry::HasSVGGlyph(uint32_t aGlyphId) { - NS_ASSERTION(mSVGInitialized, - "SVG data has not yet been loaded. TryGetSVGData() first."); + MOZ_ASSERT(mSVGInitialized, + "SVG data has not yet been loaded. TryGetSVGData() first."); return GetSVGGlyphs()->HasSVGGlyph(aGlyphId); } @@ -309,8 +319,8 @@ bool gfxFontEntry::GetSVGGlyphExtents(DrawTarget* aDrawTarget, void gfxFontEntry::RenderSVGGlyph(gfxContext* aContext, uint32_t aGlyphId, SVGContextPaint* aContextPaint) { - NS_ASSERTION(mSVGInitialized, - "SVG data has not yet been loaded. TryGetSVGData() first."); + MOZ_ASSERT(mSVGInitialized, + "SVG data has not yet been loaded. TryGetSVGData() first."); GetSVGGlyphs()->RenderGlyph(aContext, aGlyphId, aContextPaint); } @@ -467,8 +477,9 @@ hb_blob_t* gfxFontEntry::FontTableHashEntry::ShareTableAndGetBlob( HB_MEMORY_MODE_READONLY, mSharedBlobData, DeleteFontTableBlobData); if (mBlob == hb_blob_get_empty()) { // The FontTableBlobData was destroyed during hb_blob_create(). - // The (empty) blob is still be held in the hashtable with a strong + // The (empty) blob will still be held in the hashtable with a strong // reference. + mSharedBlobData = nullptr; return hb_blob_reference(mBlob); } ===================================== gfx/thebes/gfxFontEntry.h ===================================== @@ -538,6 +538,9 @@ class gfxFontEntry { mozilla::gfx::Rect GetFontExtents(float aFUnitScaleFactor) const { // Flip the y-axis here to match the orientation of Gecko's coordinates. + // We don't need to take a lock here because the min/max fields are inert + // after initialization, and we make sure to initialize them at gfxFont- + // creation time. return mozilla::gfx::Rect(float(mXMin) * aFUnitScaleFactor, float(-mYMax) * aFUnitScaleFactor, float(mXMax - mXMin) * aFUnitScaleFactor, View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/d5… -- This project does not include diff previews in email notifications. View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/d5… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/mullvad-browser][mullvad-browser-115.11.0esr-13.0-1] 3 commits: Bug 1871109 - generateHash in Manifest.sys.mjs should use sha256 r=peterv, a=dmeehan
by ma1 (@ma1) 09 May '24

09 May '24
ma1 pushed to branch mullvad-browser-115.11.0esr-13.0-1 at The Tor Project / Applications / Mullvad Browser Commits: 50b53983 by Nuohan Li at 2024-05-09T13:04:13+02:00 Bug 1871109 - generateHash in Manifest.sys.mjs should use sha256 r=peterv, a=dmeehan Differential Revision: https://phabricator.services.mozilla.com/D204928 - - - - - 7269657b by Jonathan Kew at 2024-05-09T13:04:14+02:00 Bug 1890204 - Ensure font entry&#39;s unitsPerEm and font extents are initialized when gfxFont is created. r=gfx-reviewers,lsalzman This means that by the time we potentially call GetFontExtents() when drawing, the extents fields are guaranteed to have been been initialized, and there&#39;s no risk of the (read-only) access here racing with setting them in UnitsPerEm(). Differential Revision: https://phabricator.services.mozilla.com/D206920 - - - - - b4147595 by Jonathan Kew at 2024-05-09T13:04:15+02:00 Bug 1893891 - Clear mSharedBlobData if blob creation failed. a=dmeehan Original Revision: https://phabricator.services.mozilla.com/D208983 Differential Revision: https://phabricator.services.mozilla.com/D209209 - - - - - 5 changed files: - dom/manifest/Manifest.sys.mjs - dom/manifest/test/browser_Manifest_install.js - gfx/thebes/gfxFont.cpp - gfx/thebes/gfxFontEntry.cpp - gfx/thebes/gfxFontEntry.h Changes: ===================================== dom/manifest/Manifest.sys.mjs ===================================== @@ -29,11 +29,11 @@ ChromeUtils.defineESModuleGetters(lazy, { * @note The generated hash is returned in base64 form. Mind the fact base64 * is case-sensitive if you are going to reuse this code. */ -function generateHash(aString) { +function generateHash(aString, hashAlg) { const cryptoHash = Cc["@mozilla.org/security/hash;1"].createInstance( Ci.nsICryptoHash ); - cryptoHash.init(Ci.nsICryptoHash.MD5); + cryptoHash.init(hashAlg); const stringStream = Cc[ "@mozilla.org/io/string-input-stream;1" ].createInstance(Ci.nsIStringInputStream); @@ -66,11 +66,39 @@ class Manifest { this._manifestUrl = manifestUrl; // The key for this is the manifests URL that is required to be unique. // However arbitrary urls are not safe file paths so lets hash it. - const fileName = generateHash(manifestUrl) + ".json"; - this._path = PathUtils.join(MANIFESTS_DIR, fileName); + const filename = + generateHash(manifestUrl, Ci.nsICryptoHash.SHA256) + ".json"; + this._path = PathUtils.join(MANIFESTS_DIR, filename); this.browser = browser; } + /** + * See Bug 1871109 + * This function is called at the beginning of initialize() to check if a given + * manifest has MD5 based filename, if so we remove it and migrate the content to + * a new file with SHA256 based name. + * This is done due to security concern, as MD5 is an outdated hashing algorithm and + * shouldn't be used anymore + */ + async removeMD5BasedFilename() { + const filenameMD5 = + generateHash(this._manifestUrl, Ci.nsICryptoHash.MD5) + ".json"; + const MD5Path = PathUtils.join(MANIFESTS_DIR, filenameMD5); + try { + await IOUtils.copy(MD5Path, this._path, { noOverwrite: true }); + } catch (error) { + // we are ignoring the failures returned from copy as it should not stop us from + // installing a new manifest + } + + // Remove the old MD5 based file unconditionally to ensure it's no longer used + try { + await IOUtils.remove(MD5Path); + } catch { + // ignore the error in case MD5 based file does not exist + } + } + get browser() { return this._browser; } @@ -80,6 +108,7 @@ class Manifest { } async initialize() { + await this.removeMD5BasedFilename(); this._store = new lazy.JSONFile({ path: this._path, saveDelayMs: 100 }); await this._store.load(); } ===================================== dom/manifest/test/browser_Manifest_install.js ===================================== @@ -23,18 +23,59 @@ function makeTestURL() { return url.href; } +function generateHash(aString, hashAlg) { + const cryptoHash = Cc["@mozilla.org/security/hash;1"].createInstance( + Ci.nsICryptoHash + ); + cryptoHash.init(hashAlg); + const stringStream = Cc[ + "@mozilla.org/io/string-input-stream;1" + ].createInstance(Ci.nsIStringInputStream); + stringStream.data = aString; + cryptoHash.updateFromStream(stringStream, -1); + // base64 allows the '/' char, but we can't use it for filenames. + return cryptoHash.finish(true).replace(/\//g, "-"); +} + +const MANIFESTS_DIR = PathUtils.join(PathUtils.profileDir, "manifests"); + add_task(async function () { const tabOptions = { gBrowser, url: makeTestURL() }; + const filenameMD5 = generateHash(manifestUrl, Ci.nsICryptoHash.MD5) + ".json"; + const filenameSHA = + generateHash(manifestUrl, Ci.nsICryptoHash.SHA256) + ".json"; + const manifestMD5Path = PathUtils.join(MANIFESTS_DIR, filenameMD5); + const manifestSHAPath = PathUtils.join(MANIFESTS_DIR, filenameSHA); + await BrowserTestUtils.withNewTab(tabOptions, async function (browser) { - let manifest = await Manifests.getManifest(browser, manifestUrl); - is(manifest.installed, false, "We haven't installed this manifest yet"); + let tmpManifest = await Manifests.getManifest(browser, manifestUrl); + is(tmpManifest.installed, false, "We haven't installed this manifest yet"); + + await tmpManifest.install(); + // making sure the manifest is actually installed before proceeding + await tmpManifest._store._save(); + await IOUtils.move(tmpManifest.path, manifestMD5Path); + + let exists = await IOUtils.exists(tmpManifest.path); + is( + exists, + false, + "Manually moved manifest from SHA256 based path to MD5 based path" + ); + Manifests.manifestObjs.delete(manifestUrl); + + let manifest = await Manifests.getManifest(browser, manifestUrl); await manifest.install(browser); is(manifest.name, "hello World", "Manifest has correct name"); is(manifest.installed, true, "Manifest is installed"); is(manifest.url, manifestUrl, "has correct url"); is(manifest.browser, browser, "has correct browser"); + is(manifest.path, manifestSHAPath, "has correct path"); + + exists = await IOUtils.exists(manifestMD5Path); + is(exists, false, "MD5 based manifest removed"); manifest = await Manifests.getManifest(browser, manifestUrl); is(manifest.installed, true, "New instances are installed"); ===================================== gfx/thebes/gfxFont.cpp ===================================== @@ -952,6 +952,10 @@ gfxFont::gfxFont(const RefPtr<UnscaledFont>& aUnscaledFont, } mKerningSet = HasFeatureSet(HB_TAG('k', 'e', 'r', 'n'), mKerningEnabled); + + // Ensure the gfxFontEntry's unitsPerEm and extents fields are initialized, + // so that GetFontExtents can use them without risk of races. + Unused << mFontEntry->UnitsPerEm(); } gfxFont::~gfxFont() { ===================================== gfx/thebes/gfxFontEntry.cpp ===================================== @@ -262,14 +262,22 @@ already_AddRefed<gfxFont> gfxFontEntry::FindOrMakeFont( } uint16_t gfxFontEntry::UnitsPerEm() { + { + AutoReadLock lock(mLock); + if (mUnitsPerEm) { + return mUnitsPerEm; + } + } + + AutoTable headTable(this, TRUETYPE_TAG('h', 'e', 'a', 'd')); + AutoWriteLock lock(mLock); + if (!mUnitsPerEm) { - AutoTable headTable(this, TRUETYPE_TAG('h', 'e', 'a', 'd')); if (headTable) { uint32_t len; const HeadTable* head = reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable, &len)); if (len >= sizeof(HeadTable)) { - mUnitsPerEm = head->unitsPerEm; if (int16_t(head->xMax) > int16_t(head->xMin) && int16_t(head->yMax) > int16_t(head->yMin)) { mXMin = head->xMin; @@ -277,6 +285,7 @@ uint16_t gfxFontEntry::UnitsPerEm() { mXMax = head->xMax; mYMax = head->yMax; } + mUnitsPerEm = head->unitsPerEm; } } @@ -286,12 +295,13 @@ uint16_t gfxFontEntry::UnitsPerEm() { mUnitsPerEm = kInvalidUPEM; } } + return mUnitsPerEm; } bool gfxFontEntry::HasSVGGlyph(uint32_t aGlyphId) { - NS_ASSERTION(mSVGInitialized, - "SVG data has not yet been loaded. TryGetSVGData() first."); + MOZ_ASSERT(mSVGInitialized, + "SVG data has not yet been loaded. TryGetSVGData() first."); return GetSVGGlyphs()->HasSVGGlyph(aGlyphId); } @@ -309,8 +319,8 @@ bool gfxFontEntry::GetSVGGlyphExtents(DrawTarget* aDrawTarget, void gfxFontEntry::RenderSVGGlyph(gfxContext* aContext, uint32_t aGlyphId, SVGContextPaint* aContextPaint) { - NS_ASSERTION(mSVGInitialized, - "SVG data has not yet been loaded. TryGetSVGData() first."); + MOZ_ASSERT(mSVGInitialized, + "SVG data has not yet been loaded. TryGetSVGData() first."); GetSVGGlyphs()->RenderGlyph(aContext, aGlyphId, aContextPaint); } @@ -467,8 +477,9 @@ hb_blob_t* gfxFontEntry::FontTableHashEntry::ShareTableAndGetBlob( HB_MEMORY_MODE_READONLY, mSharedBlobData, DeleteFontTableBlobData); if (mBlob == hb_blob_get_empty()) { // The FontTableBlobData was destroyed during hb_blob_create(). - // The (empty) blob is still be held in the hashtable with a strong + // The (empty) blob will still be held in the hashtable with a strong // reference. + mSharedBlobData = nullptr; return hb_blob_reference(mBlob); } ===================================== gfx/thebes/gfxFontEntry.h ===================================== @@ -538,6 +538,9 @@ class gfxFontEntry { mozilla::gfx::Rect GetFontExtents(float aFUnitScaleFactor) const { // Flip the y-axis here to match the orientation of Gecko's coordinates. + // We don't need to take a lock here because the min/max fields are inert + // after initialization, and we make sure to initialize them at gfxFont- + // creation time. return mozilla::gfx::Rect(float(mXMin) * aFUnitScaleFactor, float(-mYMax) * aFUnitScaleFactor, float(mXMax - mXMin) * aFUnitScaleFactor, View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/d3… -- This project does not include diff previews in email notifications. View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/d3… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][base-browser-115.11.0esr-13.0-1] 3 commits: Bug 1871109 - generateHash in Manifest.sys.mjs should use sha256 r=peterv, a=dmeehan
by ma1 (@ma1) 09 May '24

09 May '24
ma1 pushed to branch base-browser-115.11.0esr-13.0-1 at The Tor Project / Applications / Tor Browser Commits: ac2c9355 by Nuohan Li at 2024-05-09T13:01:34+02:00 Bug 1871109 - generateHash in Manifest.sys.mjs should use sha256 r=peterv, a=dmeehan Differential Revision: https://phabricator.services.mozilla.com/D204928 - - - - - 9d85032c by Jonathan Kew at 2024-05-09T13:01:39+02:00 Bug 1890204 - Ensure font entry&#39;s unitsPerEm and font extents are initialized when gfxFont is created. r=gfx-reviewers,lsalzman This means that by the time we potentially call GetFontExtents() when drawing, the extents fields are guaranteed to have been been initialized, and there&#39;s no risk of the (read-only) access here racing with setting them in UnitsPerEm(). Differential Revision: https://phabricator.services.mozilla.com/D206920 - - - - - 8a728aa8 by Jonathan Kew at 2024-05-09T13:01:40+02:00 Bug 1893891 - Clear mSharedBlobData if blob creation failed. a=dmeehan Original Revision: https://phabricator.services.mozilla.com/D208983 Differential Revision: https://phabricator.services.mozilla.com/D209209 - - - - - 5 changed files: - dom/manifest/Manifest.sys.mjs - dom/manifest/test/browser_Manifest_install.js - gfx/thebes/gfxFont.cpp - gfx/thebes/gfxFontEntry.cpp - gfx/thebes/gfxFontEntry.h Changes: ===================================== dom/manifest/Manifest.sys.mjs ===================================== @@ -29,11 +29,11 @@ ChromeUtils.defineESModuleGetters(lazy, { * @note The generated hash is returned in base64 form. Mind the fact base64 * is case-sensitive if you are going to reuse this code. */ -function generateHash(aString) { +function generateHash(aString, hashAlg) { const cryptoHash = Cc["@mozilla.org/security/hash;1"].createInstance( Ci.nsICryptoHash ); - cryptoHash.init(Ci.nsICryptoHash.MD5); + cryptoHash.init(hashAlg); const stringStream = Cc[ "@mozilla.org/io/string-input-stream;1" ].createInstance(Ci.nsIStringInputStream); @@ -66,11 +66,39 @@ class Manifest { this._manifestUrl = manifestUrl; // The key for this is the manifests URL that is required to be unique. // However arbitrary urls are not safe file paths so lets hash it. - const fileName = generateHash(manifestUrl) + ".json"; - this._path = PathUtils.join(MANIFESTS_DIR, fileName); + const filename = + generateHash(manifestUrl, Ci.nsICryptoHash.SHA256) + ".json"; + this._path = PathUtils.join(MANIFESTS_DIR, filename); this.browser = browser; } + /** + * See Bug 1871109 + * This function is called at the beginning of initialize() to check if a given + * manifest has MD5 based filename, if so we remove it and migrate the content to + * a new file with SHA256 based name. + * This is done due to security concern, as MD5 is an outdated hashing algorithm and + * shouldn't be used anymore + */ + async removeMD5BasedFilename() { + const filenameMD5 = + generateHash(this._manifestUrl, Ci.nsICryptoHash.MD5) + ".json"; + const MD5Path = PathUtils.join(MANIFESTS_DIR, filenameMD5); + try { + await IOUtils.copy(MD5Path, this._path, { noOverwrite: true }); + } catch (error) { + // we are ignoring the failures returned from copy as it should not stop us from + // installing a new manifest + } + + // Remove the old MD5 based file unconditionally to ensure it's no longer used + try { + await IOUtils.remove(MD5Path); + } catch { + // ignore the error in case MD5 based file does not exist + } + } + get browser() { return this._browser; } @@ -80,6 +108,7 @@ class Manifest { } async initialize() { + await this.removeMD5BasedFilename(); this._store = new lazy.JSONFile({ path: this._path, saveDelayMs: 100 }); await this._store.load(); } ===================================== dom/manifest/test/browser_Manifest_install.js ===================================== @@ -23,18 +23,59 @@ function makeTestURL() { return url.href; } +function generateHash(aString, hashAlg) { + const cryptoHash = Cc["@mozilla.org/security/hash;1"].createInstance( + Ci.nsICryptoHash + ); + cryptoHash.init(hashAlg); + const stringStream = Cc[ + "@mozilla.org/io/string-input-stream;1" + ].createInstance(Ci.nsIStringInputStream); + stringStream.data = aString; + cryptoHash.updateFromStream(stringStream, -1); + // base64 allows the '/' char, but we can't use it for filenames. + return cryptoHash.finish(true).replace(/\//g, "-"); +} + +const MANIFESTS_DIR = PathUtils.join(PathUtils.profileDir, "manifests"); + add_task(async function () { const tabOptions = { gBrowser, url: makeTestURL() }; + const filenameMD5 = generateHash(manifestUrl, Ci.nsICryptoHash.MD5) + ".json"; + const filenameSHA = + generateHash(manifestUrl, Ci.nsICryptoHash.SHA256) + ".json"; + const manifestMD5Path = PathUtils.join(MANIFESTS_DIR, filenameMD5); + const manifestSHAPath = PathUtils.join(MANIFESTS_DIR, filenameSHA); + await BrowserTestUtils.withNewTab(tabOptions, async function (browser) { - let manifest = await Manifests.getManifest(browser, manifestUrl); - is(manifest.installed, false, "We haven't installed this manifest yet"); + let tmpManifest = await Manifests.getManifest(browser, manifestUrl); + is(tmpManifest.installed, false, "We haven't installed this manifest yet"); + + await tmpManifest.install(); + // making sure the manifest is actually installed before proceeding + await tmpManifest._store._save(); + await IOUtils.move(tmpManifest.path, manifestMD5Path); + + let exists = await IOUtils.exists(tmpManifest.path); + is( + exists, + false, + "Manually moved manifest from SHA256 based path to MD5 based path" + ); + Manifests.manifestObjs.delete(manifestUrl); + + let manifest = await Manifests.getManifest(browser, manifestUrl); await manifest.install(browser); is(manifest.name, "hello World", "Manifest has correct name"); is(manifest.installed, true, "Manifest is installed"); is(manifest.url, manifestUrl, "has correct url"); is(manifest.browser, browser, "has correct browser"); + is(manifest.path, manifestSHAPath, "has correct path"); + + exists = await IOUtils.exists(manifestMD5Path); + is(exists, false, "MD5 based manifest removed"); manifest = await Manifests.getManifest(browser, manifestUrl); is(manifest.installed, true, "New instances are installed"); ===================================== gfx/thebes/gfxFont.cpp ===================================== @@ -952,6 +952,10 @@ gfxFont::gfxFont(const RefPtr<UnscaledFont>& aUnscaledFont, } mKerningSet = HasFeatureSet(HB_TAG('k', 'e', 'r', 'n'), mKerningEnabled); + + // Ensure the gfxFontEntry's unitsPerEm and extents fields are initialized, + // so that GetFontExtents can use them without risk of races. + Unused << mFontEntry->UnitsPerEm(); } gfxFont::~gfxFont() { ===================================== gfx/thebes/gfxFontEntry.cpp ===================================== @@ -262,14 +262,22 @@ already_AddRefed<gfxFont> gfxFontEntry::FindOrMakeFont( } uint16_t gfxFontEntry::UnitsPerEm() { + { + AutoReadLock lock(mLock); + if (mUnitsPerEm) { + return mUnitsPerEm; + } + } + + AutoTable headTable(this, TRUETYPE_TAG('h', 'e', 'a', 'd')); + AutoWriteLock lock(mLock); + if (!mUnitsPerEm) { - AutoTable headTable(this, TRUETYPE_TAG('h', 'e', 'a', 'd')); if (headTable) { uint32_t len; const HeadTable* head = reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable, &len)); if (len >= sizeof(HeadTable)) { - mUnitsPerEm = head->unitsPerEm; if (int16_t(head->xMax) > int16_t(head->xMin) && int16_t(head->yMax) > int16_t(head->yMin)) { mXMin = head->xMin; @@ -277,6 +285,7 @@ uint16_t gfxFontEntry::UnitsPerEm() { mXMax = head->xMax; mYMax = head->yMax; } + mUnitsPerEm = head->unitsPerEm; } } @@ -286,12 +295,13 @@ uint16_t gfxFontEntry::UnitsPerEm() { mUnitsPerEm = kInvalidUPEM; } } + return mUnitsPerEm; } bool gfxFontEntry::HasSVGGlyph(uint32_t aGlyphId) { - NS_ASSERTION(mSVGInitialized, - "SVG data has not yet been loaded. TryGetSVGData() first."); + MOZ_ASSERT(mSVGInitialized, + "SVG data has not yet been loaded. TryGetSVGData() first."); return GetSVGGlyphs()->HasSVGGlyph(aGlyphId); } @@ -309,8 +319,8 @@ bool gfxFontEntry::GetSVGGlyphExtents(DrawTarget* aDrawTarget, void gfxFontEntry::RenderSVGGlyph(gfxContext* aContext, uint32_t aGlyphId, SVGContextPaint* aContextPaint) { - NS_ASSERTION(mSVGInitialized, - "SVG data has not yet been loaded. TryGetSVGData() first."); + MOZ_ASSERT(mSVGInitialized, + "SVG data has not yet been loaded. TryGetSVGData() first."); GetSVGGlyphs()->RenderGlyph(aContext, aGlyphId, aContextPaint); } @@ -467,8 +477,9 @@ hb_blob_t* gfxFontEntry::FontTableHashEntry::ShareTableAndGetBlob( HB_MEMORY_MODE_READONLY, mSharedBlobData, DeleteFontTableBlobData); if (mBlob == hb_blob_get_empty()) { // The FontTableBlobData was destroyed during hb_blob_create(). - // The (empty) blob is still be held in the hashtable with a strong + // The (empty) blob will still be held in the hashtable with a strong // reference. + mSharedBlobData = nullptr; return hb_blob_reference(mBlob); } ===================================== gfx/thebes/gfxFontEntry.h ===================================== @@ -538,6 +538,9 @@ class gfxFontEntry { mozilla::gfx::Rect GetFontExtents(float aFUnitScaleFactor) const { // Flip the y-axis here to match the orientation of Gecko's coordinates. + // We don't need to take a lock here because the min/max fields are inert + // after initialization, and we make sure to initialize them at gfxFont- + // creation time. return mozilla::gfx::Rect(float(mXMin) * aFUnitScaleFactor, float(-mYMax) * aFUnitScaleFactor, float(mXMax - mXMin) * aFUnitScaleFactor, View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/5cc512… -- This project does not include diff previews in email notifications. View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/5cc512… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][tor-browser-115.11.0esr-13.0-1] 3 commits: Bug 1871109 - generateHash in Manifest.sys.mjs should use sha256 r=peterv, a=dmeehan
by ma1 (@ma1) 09 May '24

09 May '24
ma1 pushed to branch tor-browser-115.11.0esr-13.0-1 at The Tor Project / Applications / Tor Browser Commits: a52dc31b by Nuohan Li at 2024-05-09T10:55:04+00:00 Bug 1871109 - generateHash in Manifest.sys.mjs should use sha256 r=peterv, a=dmeehan Differential Revision: https://phabricator.services.mozilla.com/D204928 - - - - - 88affd4a by Jonathan Kew at 2024-05-09T10:55:04+00:00 Bug 1890204 - Ensure font entry&#39;s unitsPerEm and font extents are initialized when gfxFont is created. r=gfx-reviewers,lsalzman This means that by the time we potentially call GetFontExtents() when drawing, the extents fields are guaranteed to have been been initialized, and there&#39;s no risk of the (read-only) access here racing with setting them in UnitsPerEm(). Differential Revision: https://phabricator.services.mozilla.com/D206920 - - - - - fc0ee191 by Jonathan Kew at 2024-05-09T10:55:04+00:00 Bug 1893891 - Clear mSharedBlobData if blob creation failed. a=dmeehan Original Revision: https://phabricator.services.mozilla.com/D208983 Differential Revision: https://phabricator.services.mozilla.com/D209209 - - - - - 5 changed files: - dom/manifest/Manifest.sys.mjs - dom/manifest/test/browser_Manifest_install.js - gfx/thebes/gfxFont.cpp - gfx/thebes/gfxFontEntry.cpp - gfx/thebes/gfxFontEntry.h Changes: ===================================== dom/manifest/Manifest.sys.mjs ===================================== @@ -29,11 +29,11 @@ ChromeUtils.defineESModuleGetters(lazy, { * @note The generated hash is returned in base64 form. Mind the fact base64 * is case-sensitive if you are going to reuse this code. */ -function generateHash(aString) { +function generateHash(aString, hashAlg) { const cryptoHash = Cc["@mozilla.org/security/hash;1"].createInstance( Ci.nsICryptoHash ); - cryptoHash.init(Ci.nsICryptoHash.MD5); + cryptoHash.init(hashAlg); const stringStream = Cc[ "@mozilla.org/io/string-input-stream;1" ].createInstance(Ci.nsIStringInputStream); @@ -66,11 +66,39 @@ class Manifest { this._manifestUrl = manifestUrl; // The key for this is the manifests URL that is required to be unique. // However arbitrary urls are not safe file paths so lets hash it. - const fileName = generateHash(manifestUrl) + ".json"; - this._path = PathUtils.join(MANIFESTS_DIR, fileName); + const filename = + generateHash(manifestUrl, Ci.nsICryptoHash.SHA256) + ".json"; + this._path = PathUtils.join(MANIFESTS_DIR, filename); this.browser = browser; } + /** + * See Bug 1871109 + * This function is called at the beginning of initialize() to check if a given + * manifest has MD5 based filename, if so we remove it and migrate the content to + * a new file with SHA256 based name. + * This is done due to security concern, as MD5 is an outdated hashing algorithm and + * shouldn't be used anymore + */ + async removeMD5BasedFilename() { + const filenameMD5 = + generateHash(this._manifestUrl, Ci.nsICryptoHash.MD5) + ".json"; + const MD5Path = PathUtils.join(MANIFESTS_DIR, filenameMD5); + try { + await IOUtils.copy(MD5Path, this._path, { noOverwrite: true }); + } catch (error) { + // we are ignoring the failures returned from copy as it should not stop us from + // installing a new manifest + } + + // Remove the old MD5 based file unconditionally to ensure it's no longer used + try { + await IOUtils.remove(MD5Path); + } catch { + // ignore the error in case MD5 based file does not exist + } + } + get browser() { return this._browser; } @@ -80,6 +108,7 @@ class Manifest { } async initialize() { + await this.removeMD5BasedFilename(); this._store = new lazy.JSONFile({ path: this._path, saveDelayMs: 100 }); await this._store.load(); } ===================================== dom/manifest/test/browser_Manifest_install.js ===================================== @@ -23,18 +23,59 @@ function makeTestURL() { return url.href; } +function generateHash(aString, hashAlg) { + const cryptoHash = Cc["@mozilla.org/security/hash;1"].createInstance( + Ci.nsICryptoHash + ); + cryptoHash.init(hashAlg); + const stringStream = Cc[ + "@mozilla.org/io/string-input-stream;1" + ].createInstance(Ci.nsIStringInputStream); + stringStream.data = aString; + cryptoHash.updateFromStream(stringStream, -1); + // base64 allows the '/' char, but we can't use it for filenames. + return cryptoHash.finish(true).replace(/\//g, "-"); +} + +const MANIFESTS_DIR = PathUtils.join(PathUtils.profileDir, "manifests"); + add_task(async function () { const tabOptions = { gBrowser, url: makeTestURL() }; + const filenameMD5 = generateHash(manifestUrl, Ci.nsICryptoHash.MD5) + ".json"; + const filenameSHA = + generateHash(manifestUrl, Ci.nsICryptoHash.SHA256) + ".json"; + const manifestMD5Path = PathUtils.join(MANIFESTS_DIR, filenameMD5); + const manifestSHAPath = PathUtils.join(MANIFESTS_DIR, filenameSHA); + await BrowserTestUtils.withNewTab(tabOptions, async function (browser) { - let manifest = await Manifests.getManifest(browser, manifestUrl); - is(manifest.installed, false, "We haven't installed this manifest yet"); + let tmpManifest = await Manifests.getManifest(browser, manifestUrl); + is(tmpManifest.installed, false, "We haven't installed this manifest yet"); + + await tmpManifest.install(); + // making sure the manifest is actually installed before proceeding + await tmpManifest._store._save(); + await IOUtils.move(tmpManifest.path, manifestMD5Path); + + let exists = await IOUtils.exists(tmpManifest.path); + is( + exists, + false, + "Manually moved manifest from SHA256 based path to MD5 based path" + ); + Manifests.manifestObjs.delete(manifestUrl); + + let manifest = await Manifests.getManifest(browser, manifestUrl); await manifest.install(browser); is(manifest.name, "hello World", "Manifest has correct name"); is(manifest.installed, true, "Manifest is installed"); is(manifest.url, manifestUrl, "has correct url"); is(manifest.browser, browser, "has correct browser"); + is(manifest.path, manifestSHAPath, "has correct path"); + + exists = await IOUtils.exists(manifestMD5Path); + is(exists, false, "MD5 based manifest removed"); manifest = await Manifests.getManifest(browser, manifestUrl); is(manifest.installed, true, "New instances are installed"); ===================================== gfx/thebes/gfxFont.cpp ===================================== @@ -952,6 +952,10 @@ gfxFont::gfxFont(const RefPtr<UnscaledFont>& aUnscaledFont, } mKerningSet = HasFeatureSet(HB_TAG('k', 'e', 'r', 'n'), mKerningEnabled); + + // Ensure the gfxFontEntry's unitsPerEm and extents fields are initialized, + // so that GetFontExtents can use them without risk of races. + Unused << mFontEntry->UnitsPerEm(); } gfxFont::~gfxFont() { ===================================== gfx/thebes/gfxFontEntry.cpp ===================================== @@ -262,14 +262,22 @@ already_AddRefed<gfxFont> gfxFontEntry::FindOrMakeFont( } uint16_t gfxFontEntry::UnitsPerEm() { + { + AutoReadLock lock(mLock); + if (mUnitsPerEm) { + return mUnitsPerEm; + } + } + + AutoTable headTable(this, TRUETYPE_TAG('h', 'e', 'a', 'd')); + AutoWriteLock lock(mLock); + if (!mUnitsPerEm) { - AutoTable headTable(this, TRUETYPE_TAG('h', 'e', 'a', 'd')); if (headTable) { uint32_t len; const HeadTable* head = reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable, &len)); if (len >= sizeof(HeadTable)) { - mUnitsPerEm = head->unitsPerEm; if (int16_t(head->xMax) > int16_t(head->xMin) && int16_t(head->yMax) > int16_t(head->yMin)) { mXMin = head->xMin; @@ -277,6 +285,7 @@ uint16_t gfxFontEntry::UnitsPerEm() { mXMax = head->xMax; mYMax = head->yMax; } + mUnitsPerEm = head->unitsPerEm; } } @@ -286,12 +295,13 @@ uint16_t gfxFontEntry::UnitsPerEm() { mUnitsPerEm = kInvalidUPEM; } } + return mUnitsPerEm; } bool gfxFontEntry::HasSVGGlyph(uint32_t aGlyphId) { - NS_ASSERTION(mSVGInitialized, - "SVG data has not yet been loaded. TryGetSVGData() first."); + MOZ_ASSERT(mSVGInitialized, + "SVG data has not yet been loaded. TryGetSVGData() first."); return GetSVGGlyphs()->HasSVGGlyph(aGlyphId); } @@ -309,8 +319,8 @@ bool gfxFontEntry::GetSVGGlyphExtents(DrawTarget* aDrawTarget, void gfxFontEntry::RenderSVGGlyph(gfxContext* aContext, uint32_t aGlyphId, SVGContextPaint* aContextPaint) { - NS_ASSERTION(mSVGInitialized, - "SVG data has not yet been loaded. TryGetSVGData() first."); + MOZ_ASSERT(mSVGInitialized, + "SVG data has not yet been loaded. TryGetSVGData() first."); GetSVGGlyphs()->RenderGlyph(aContext, aGlyphId, aContextPaint); } @@ -467,8 +477,9 @@ hb_blob_t* gfxFontEntry::FontTableHashEntry::ShareTableAndGetBlob( HB_MEMORY_MODE_READONLY, mSharedBlobData, DeleteFontTableBlobData); if (mBlob == hb_blob_get_empty()) { // The FontTableBlobData was destroyed during hb_blob_create(). - // The (empty) blob is still be held in the hashtable with a strong + // The (empty) blob will still be held in the hashtable with a strong // reference. + mSharedBlobData = nullptr; return hb_blob_reference(mBlob); } ===================================== gfx/thebes/gfxFontEntry.h ===================================== @@ -538,6 +538,9 @@ class gfxFontEntry { mozilla::gfx::Rect GetFontExtents(float aFUnitScaleFactor) const { // Flip the y-axis here to match the orientation of Gecko's coordinates. + // We don't need to take a lock here because the min/max fields are inert + // after initialization, and we make sure to initialize them at gfxFont- + // creation time. return mozilla::gfx::Rect(float(mXMin) * aFUnitScaleFactor, float(-mYMax) * aFUnitScaleFactor, float(mXMax - mXMin) * aFUnitScaleFactor, View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/10474e… -- This project does not include diff previews in email notifications. View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/10474e… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
  • ← Newer
  • 1
  • ...
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.