diff --git a/CVE-2020-26979.patch b/CVE-2020-26979.patch new file mode 100644 index 0000000000000000000000000000000000000000..7947a4785c89a2ad74df2beb3e2d73181474f14e --- /dev/null +++ b/CVE-2020-26979.patch @@ -0,0 +1,311 @@ +From 36d469443d498a2b24079776b6e24afbd9fa7248 Mon Sep 17 00:00:00 2001 +From: Daisuke Akatsuka +Date: Mon, 26 Oct 2020 05:30:44 +0000 (2020-10-26) +Subject: [PATCH] CVE-2020-26979 + +--- + browser/base/content/utilityOverlay.js | 7 +- + browser/components/urlbar/UrlbarInput.jsm | 63 +++++++++-- + .../urlbar/tests/browser/browser_enter.js | 100 ++++++++++++++++-- + 3 files changed, 147 insertions(+), 23 deletions(-) + +diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js +index a23d6f05e6..c9d0ef8a71 100644 +--- a/browser/base/content/utilityOverlay.js ++++ b/browser/base/content/utilityOverlay.js +@@ -695,8 +695,11 @@ function openLinkIn(url, where, params) { + } + break; + } +- +- if (!focusUrlBar && targetBrowser == w.gBrowser.selectedBrowser) { ++ if ( ++ !params.avoidBrowserFocus && ++ !focusUrlBar && ++ targetBrowser == w.gBrowser.selectedBrowser ++ ) { + // Focus the content, but only if the browser used for the load is selected. + targetBrowser.focus(); + } +diff --git a/browser/components/urlbar/UrlbarInput.jsm b/browser/components/urlbar/UrlbarInput.jsm +index 366149ec07..b9a916ca1b 100644 +--- a/browser/components/urlbar/UrlbarInput.jsm ++++ b/browser/components/urlbar/UrlbarInput.jsm +@@ -16,6 +16,7 @@ XPCOMUtils.defineLazyModuleGetters(this, { + ExtensionSearchHandler: "resource://gre/modules/ExtensionSearchHandler.jsm", + FormHistory: "resource://gre/modules/FormHistory.jsm", + PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm", ++ PromiseUtils: "resource://gre/modules/PromiseUtils.jsm", + ReaderMode: "resource://gre/modules/ReaderMode.jsm", + Services: "resource://gre/modules/Services.jsm", + TopSiteAttribution: "resource:///modules/TopSiteAttribution.jsm", +@@ -474,7 +475,7 @@ class UrlbarInput { + isValidUrl = true; + } catch (ex) {} + if (isValidUrl) { +- this._loadURL(url, where, openParams); ++ this._loadURL(url, event, where, openParams); + return; + } + +@@ -528,8 +529,8 @@ class UrlbarInput { + browser.lastLocationChange == lastLocationChange + ) { + openParams.postData = postData.value; +- this._loadURL(uri.spec, where, openParams, null, browser); +- } ++ this._loadURL(uri.spec, event, where, openParams, null, browser); ++ } + } + }); + // Don't add further handling here, the catch above is our last resort. +@@ -600,8 +601,8 @@ class UrlbarInput { + selIndex, + selType: "canonized", + }); +- this._loadURL(this.value, where, openParams, browser); +- return; ++ this._loadURL(this.value, event, where, openParams, browser); ++ return; + } + + let { url, postData } = UrlbarUtils.getUrlFromResult(result); +@@ -844,6 +845,7 @@ class UrlbarInput { + + this._loadURL( + url, ++ event, + where, + openParams, + { +@@ -1757,6 +1759,8 @@ class UrlbarInput { + * + * @param {string} url + * The URL to open. ++ @param {Event} event ++ * The event that triggered to load the url. + * @param {string} openUILinkWhere + * Where we expect the result to be opened. + * @param {object} params +@@ -1778,6 +1782,7 @@ class UrlbarInput { + */ + _loadURL( + url, ++ event, + openUILinkWhere, + params, + resultDetails = null, +@@ -1835,12 +1840,19 @@ class UrlbarInput { + } else { + params.initiatingDoc = this.window.document; + } ++ if (event?.keyCode === KeyEvent.DOM_VK_RETURN) { ++ if (openUILinkWhere === "current") { ++ params.avoidBrowserFocus = true; ++ this._keyDownEnterDeferred?.resolve(browser); ++ } ++ } + + // Focus the content area before triggering loads, since if the load + // occurs in a new tab, we want focus to be restored to the content + // area when the current tab is re-selected. +- browser.focus(); +- ++ if (!params.avoidBrowserFocus) { ++ browser.focus(); ++ } + if (openUILinkWhere != "current") { + this.handleRevert(); + } +@@ -2059,7 +2071,14 @@ class UrlbarInput { + ) { + this.window.UpdatePopupNotificationsVisibility(); + } +- ++ ++ // If user move the focus to another component while pressing Enter key, ++ // then keyup at that component, as we can't get the event, clear the promise. ++ if (this._keyDownEnterDeferred) { ++ this._keyDownEnterDeferred.resolve(); ++ this._keyDownEnterDeferred = null; ++ } ++ + Services.obs.notifyObservers(null, "urlbar-blur"); + } + +@@ -2376,6 +2395,12 @@ class UrlbarInput { + } + + _on_keydown(event) { ++ if (event.keyCode === KeyEvent.DOM_VK_RETURN) { ++ if (this._keyDownEnterDeferred) { ++ this._keyDownEnterDeferred.reject(); ++ } ++ this._keyDownEnterDeferred = PromiseUtils.defer(); ++ } + // Due to event deferring, it's possible preventDefault() won't be invoked + // soon enough to actually prevent some of the default behaviors, thus we + // have to handle the event "twice". This first immediate call passes false +@@ -2391,9 +2416,27 @@ class UrlbarInput { + this.controller.handleKeyNavigation(event); + }); + } ++ ++ async _on_keyup(event) { ++ if ( ++ event.keyCode === KeyEvent.DOM_VK_RETURN && ++ this._keyDownEnterDeferred ++ ) { ++ try { ++ const loadingBrowser = await this._keyDownEnterDeferred.promise; ++ // Ensure the selected browser didn't change in the meanwhile. ++ if (this.window.gBrowser.selectedBrowser === loadingBrowser) { ++ loadingBrowser.focus(); ++ } ++ } catch (ex) { ++ // Not all the Enter actions in the urlbar will cause a navigation, then it ++ // is normal for this to be rejected. ++ } ++ this._keyDownEnterDeferred = null; ++ return; ++ } + +- _on_keyup(event) { +- this._toggleActionOverride(event); ++ this._toggleActionOverride(event); + } + + _on_compositionstart(event) { +diff --git a/browser/components/urlbar/tests/browser/browser_enter.js b/browser/components/urlbar/tests/browser/browser_enter.js +index 3eb6df89c7..6d89815345 100644 +--- a/browser/components/urlbar/tests/browser/browser_enter.js ++++ b/browser/components/urlbar/tests/browser/browser_enter.js +@@ -6,6 +6,20 @@ + const TEST_VALUE = "example.com/\xF7?\xF7"; + const START_VALUE = "example.com/%C3%B7?%C3%B7"; + ++add_task(async function setup() { ++ const engine = await SearchTestUtils.promiseNewSearchEngine( ++ getRootDirectory(gTestPath) + "searchSuggestionEngine.xml" ++ ); ++ ++ const defaultEngine = Services.search.defaultEngine; ++ Services.search.defaultEngine = engine; ++ ++ registerCleanupFunction(async function() { ++ Services.search.defaultEngine = defaultEngine; ++ }); ++}); ++ ++ + add_task(async function returnKeypress() { + info("Simple return keypress"); + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, START_VALUE); +@@ -82,12 +96,7 @@ add_task(async function altGrReturnKeypress() { + + add_task(async function searchOnEnterNoPick() { + info("Search on Enter without picking a urlbar result"); +- let engine = await SearchTestUtils.promiseNewSearchEngine( +- getRootDirectory(gTestPath) + "searchSuggestionEngine.xml" +- ); +- let defaultEngine = Services.search.defaultEngine; +- Services.search.defaultEngine = engine; +- // Why is BrowserTestUtils.openNewForegroundTab not causing the bug? ++ // Why is BrowserTestUtils.openNewForegroundTab not causing the bug? + let promiseTabOpened = BrowserTestUtils.waitForEvent( + gBrowser.tabContainer, + "TabOpen" +@@ -95,11 +104,7 @@ add_task(async function searchOnEnterNoPick() { + EventUtils.synthesizeMouseAtCenter(gBrowser.tabContainer.newTabButton, {}); + let openEvent = await promiseTabOpened; + let tab = openEvent.target; +- registerCleanupFunction(async function() { +- Services.search.defaultEngine = defaultEngine; +- BrowserTestUtils.removeTab(tab); +- }); +- ++ + let loadPromise = BrowserTestUtils.browserLoaded( + gBrowser.selectedBrowser, + false, +@@ -120,4 +125,77 @@ add_task(async function searchOnEnterNoPick() { + gURLBar.untrimmedValue, + "The location should have changed" + ); ++ ++ // Cleanup. ++ BrowserTestUtils.removeTab(tab); ++}); ++ ++add_task(async function searchOnEnterSoon() { ++ info("Search on Enter as soon as typing a char"); ++ const tab = await BrowserTestUtils.openNewForegroundTab( ++ gBrowser, ++ START_VALUE ++ ); ++ ++ const onLoad = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); ++ const onBeforeUnload = SpecialPowers.spawn( ++ gBrowser.selectedBrowser, ++ [], ++ () => { ++ return new Promise(resolve => { ++ content.window.addEventListener("beforeunload", () => { ++ resolve(); ++ }); ++ }); ++ } ++ ); ++ const onResult = SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => { ++ return new Promise(resolve => { ++ content.window.addEventListener("keyup", () => { ++ resolve("keyup"); ++ }); ++ content.window.addEventListener("unload", () => { ++ resolve("unload"); ++ }); ++ }); ++ }); ++ ++ // Focus on the input field in urlbar. ++ EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {}); ++ const ownerDocument = gBrowser.selectedBrowser.ownerDocument; ++ is( ++ ownerDocument.activeElement, ++ gURLBar.inputField, ++ "The input field in urlbar has focus" ++ ); ++ ++ info("Keydown a char and Enter"); ++ EventUtils.synthesizeKey("x", { type: "keydown" }); ++ EventUtils.synthesizeKey("KEY_Enter", { type: "keydown" }); ++ ++ // Wait for beforeUnload event in the content. ++ await onBeforeUnload; ++ is( ++ ownerDocument.activeElement, ++ gURLBar.inputField, ++ "The input field in urlbar still has focus" ++ ); ++ ++ // Keyup both key as soon as beforeUnload event happens. ++ EventUtils.synthesizeKey("x", { type: "keyup" }); ++ EventUtils.synthesizeKey("KEY_Enter", { type: "keyup" }); ++ ++ // Wait for moving the focus. ++ await TestUtils.waitForCondition( ++ () => ownerDocument.activeElement === gBrowser.selectedBrowser ++ ); ++ info("The focus is moved to the browser"); ++ ++ // Check whether keyup event is not captured before unload event happens. ++ const result = await onResult; ++ is(result, "unload", "Keyup event is not captured."); ++ ++ // Cleanup. ++ await onLoad; ++ BrowserTestUtils.removeTab(tab); + }); +-- +2.27.0 + diff --git a/firefox.spec b/firefox.spec index 54227991f47c5843ce1ddd2f070d43473a55841b..f21e052ef0ea2759df5b37839358388eed460d09 100644 --- a/firefox.spec +++ b/firefox.spec @@ -88,7 +88,7 @@ Summary: Mozilla Firefox Web browser Name: firefox Version: 79.0 -Release: 22 +Release: 23 URL: https://www.mozilla.org/firefox/ License: MPLv1.1 or GPLv2+ or LGPLv2+ Source0: https://archive.mozilla.org/pub/firefox/releases/%{version}/source/firefox-%{version}.source.tar.xz @@ -201,6 +201,7 @@ Patch657: CVE-2020-26950.patch Patch658: CVE-2020-26971.patch Patch659: CVE-2021-29946.patch Patch660: CVE-2022-34481.patch +Patch661: CVE-2020-26979.patch %if %{?system_nss} BuildRequires: pkgconfig(nspr) >= %{nspr_version} pkgconfig(nss) >= %{nss_version} @@ -396,6 +397,7 @@ tar -xf %{SOURCE3} %patch658 -p1 %patch659 -p1 %patch660 -p1 +%patch661 -p1 %{__rm} -f .mozconfig %{__cp} %{SOURCE10} .mozconfig @@ -844,6 +846,9 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : %endif %changelog +* Wed Jun 5 2024 lvfei - 79.0-23 +- Fix CVE-2020-26979 + * Mon May 27 2024 lvfei - 79.0-22 - Fix CVE-2022-34481