Bug 1959370 - Add an ability to disable and enable security checks per user context for testing. r=keeler

Differential Revision: https://phabricator.services.mozilla.com/D247746
This commit is contained in:
Alexandra Borovova
2025-05-21 07:28:56 +00:00
committed by aborovova@mozilla.com
parent 742b637921
commit 6a615f57fc
5 changed files with 301 additions and 3 deletions

View File

@@ -433,7 +433,14 @@ nsCertOverrideService::HasMatchingOverride(
bool disableAllSecurityCheck = false;
{
MutexAutoLock lock(mMutex);
disableAllSecurityCheck = mDisableAllSecurityCheck;
if (mUserContextIdsWithSecurityChecksOverride.has(
aOriginAttributes.mUserContextId)) {
auto p = mUserContextIdsWithSecurityChecksOverride.lookup(
aOriginAttributes.mUserContextId);
disableAllSecurityCheck = p->value();
} else {
disableAllSecurityCheck = mDisableAllSecurityCheck;
}
}
if (disableAllSecurityCheck) {
*aIsTemporary = false;
@@ -665,6 +672,39 @@ nsCertOverrideService::
return NS_OK;
}
NS_IMETHODIMP
nsCertOverrideService::
SetDisableAllSecurityChecksAndLetAttackersInterceptMyDataForUserContext(
uint32_t aUserContextId, bool aDisable) {
if (!(PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR") || IsDebugger())) {
return NS_ERROR_NOT_AVAILABLE;
}
{
MutexAutoLock lock(mMutex);
mozilla::Unused << mUserContextIdsWithSecurityChecksOverride.put(
aUserContextId, aDisable);
}
return NS_OK;
}
NS_IMETHODIMP
nsCertOverrideService::
ResetDisableAllSecurityChecksAndLetAttackersInterceptMyDataForUserContext(
uint32_t aUserContextId) {
if (!(PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR") || IsDebugger())) {
return NS_ERROR_NOT_AVAILABLE;
}
{
MutexAutoLock lock(mMutex);
mUserContextIdsWithSecurityChecksOverride.remove(aUserContextId);
}
return NS_OK;
}
NS_IMETHODIMP
nsCertOverrideService::GetSecurityCheckDisabled(bool* aDisabled) {
MutexAutoLock lock(mMutex);

View File

@@ -118,6 +118,8 @@ class nsCertOverrideService final : public nsICertOverrideService,
mozilla::Mutex mMutex;
bool mDisableAllSecurityCheck MOZ_GUARDED_BY(mMutex);
mozilla::HashMap<uint32_t, bool> mUserContextIdsWithSecurityChecksOverride
MOZ_GUARDED_BY(mMutex);
nsCOMPtr<nsIFile> mSettingsFile MOZ_GUARDED_BY(mMutex);
nsTHashtable<nsCertOverrideEntry> mSettingsTable MOZ_GUARDED_BY(mMutex);

View File

@@ -134,10 +134,43 @@ interface nsICertOverrideService : nsISupports {
/**
* NOTE: This function is used only for testing!
*
* @param aDisable If true, disable all security check and make
* @param aDisable If true, disable all security checks and make
* hasMatchingOverride always return true.
*/
void setDisableAllSecurityChecksAndLetAttackersInterceptMyData(in boolean aDisable);
void setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
in boolean aDisable);
/**
* NOTE: This function is used only for webdriver!
* Spec: https://www.w3.org/TR/webdriver-bidi/#command-browser-createUserContext.
*
* The method is designed to enable or disable all security checks
* for the specified user context. This settings should override the global state,
* e.g., the security checks can be disabled globally but with this method they can
* be enabled for the specified user context.
*
* @param aUserContextId Enable or disable all security checks for this user context.
* @param aDisable If true, disable all security checks and make
* hasMatchingOverride always return true.
*/
void setDisableAllSecurityChecksAndLetAttackersInterceptMyDataForUserContext(
in uint32_t aUserContextId,
in boolean aDisable);
/**
* NOTE: This function is used only for webdriver!
* Spec: https://www.w3.org/TR/webdriver-bidi/#cleanup-the-session.
*
* This method is required to reset the status of security checks
* for the specified user context and fallback to the global state.
* E.g., the user context can have security checks enabled
* but globally they are disabled. After calling this method the security checks
* for the user context should be disabled as it is globally.
*
* @param aUserContextId Reset the status of security checks for this user context.
*/
void resetDisableAllSecurityChecksAndLetAttackersInterceptMyDataForUserContext(
in uint32_t aUserContextId);
readonly attribute boolean securityCheckDisabled;
};

View File

@@ -52,3 +52,5 @@ skip-if = ["os == 'linux'"]
["browser_exportP12_passwordUI.js"]
["browser_loadPKCS11Module_ui.js"]
["browser_setDisableAllSecurityChecksAndLetAttackersInterceptMyData.js"]

View File

@@ -0,0 +1,221 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { ContextualIdentityListener } = ChromeUtils.importESModule(
"chrome://remote/content/shared/listeners/ContextualIdentityListener.sys.mjs"
);
const PAGE_URL = "https://example.com/";
const PAGE_WITH_EXPIRED_CERT = "https://expired.example.com/";
add_task(async function test_disable_all_security_checks_globally() {
const certOverrideService = Cc[
"@mozilla.org/security/certoverride;1"
].getService(Ci.nsICertOverrideService);
const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE_URL);
const browser = gBrowser.selectedBrowser;
info("Loading and waiting for the cert error");
let errorPageLoaded = BrowserTestUtils.waitForErrorPage(browser);
BrowserTestUtils.startLoadingURIString(browser, PAGE_WITH_EXPIRED_CERT);
await errorPageLoaded;
Assert.ok(true, "Error page is loaded");
info("Disable security checks");
certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
true
);
const loadedPromise = BrowserTestUtils.browserLoaded(browser);
BrowserTestUtils.startLoadingURIString(browser, PAGE_WITH_EXPIRED_CERT);
await loadedPromise;
Assert.ok(true, "Normal page is loaded");
info("Enable security checks");
certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
false
);
errorPageLoaded = BrowserTestUtils.waitForErrorPage(browser);
BrowserTestUtils.startLoadingURIString(browser, PAGE_WITH_EXPIRED_CERT);
await errorPageLoaded;
Assert.ok(true, "Error page is loaded");
BrowserTestUtils.removeTab(tab);
});
add_task(async function test_disable_all_security_checks_for_user_context() {
const certOverrideService = Cc[
"@mozilla.org/security/certoverride;1"
].getService(Ci.nsICertOverrideService);
const userContext = ContextualIdentityService.create("test_name");
const { userContextId } = userContext;
const tabInUserContext = BrowserTestUtils.addTab(gBrowser, PAGE_URL, {
userContextId,
});
const browserInUserContext = tabInUserContext.linkedBrowser;
info("Loading and waiting for the cert error in user context");
let errorPageLoaded = BrowserTestUtils.waitForErrorPage(browserInUserContext);
BrowserTestUtils.startLoadingURIString(
browserInUserContext,
PAGE_WITH_EXPIRED_CERT
);
await errorPageLoaded;
Assert.ok(true, "Error page is loaded");
info("Disable security checks for user context");
certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyDataForUserContext(
userContextId,
true
);
let loadedPromise = BrowserTestUtils.browserLoaded(browserInUserContext);
BrowserTestUtils.startLoadingURIString(
browserInUserContext,
PAGE_WITH_EXPIRED_CERT
);
await loadedPromise;
Assert.ok(true, "Normal page is loaded in user context");
const tabInDefaultUserContext = BrowserTestUtils.addTab(gBrowser, PAGE_URL);
const browserInDefaultUserContext = tabInDefaultUserContext.linkedBrowser;
info("Loading and waiting for the cert error in default user context");
errorPageLoaded = BrowserTestUtils.waitForErrorPage(
browserInDefaultUserContext
);
BrowserTestUtils.startLoadingURIString(
browserInDefaultUserContext,
PAGE_WITH_EXPIRED_CERT
);
await errorPageLoaded;
Assert.ok(true, "Error page is loaded");
BrowserTestUtils.removeTab(tabInUserContext);
BrowserTestUtils.removeTab(tabInDefaultUserContext);
ContextualIdentityService.remove(userContextId);
});
add_task(
async function test_disable_all_security_checks_globally_enable_for_user_context() {
const certOverrideService = Cc[
"@mozilla.org/security/certoverride;1"
].getService(Ci.nsICertOverrideService);
const tabInDefaultUserContext = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
PAGE_URL
);
const browser = gBrowser.selectedBrowser;
info("Disable security checks");
certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
true
);
let loadedPromise = BrowserTestUtils.browserLoaded(browser);
BrowserTestUtils.startLoadingURIString(browser, PAGE_WITH_EXPIRED_CERT);
await loadedPromise;
Assert.ok(true, "Normal page is loaded");
const userContext = ContextualIdentityService.create("test_name");
const { userContextId } = userContext;
const tabInUserContext = BrowserTestUtils.addTab(gBrowser, PAGE_URL, {
userContextId,
});
const browserInUserContext = tabInUserContext.linkedBrowser;
info("Enable security checks for user context");
certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyDataForUserContext(
userContextId,
false
);
info("Loading and waiting for the cert error in user context");
const errorPageLoaded =
BrowserTestUtils.waitForErrorPage(browserInUserContext);
BrowserTestUtils.startLoadingURIString(
browserInUserContext,
PAGE_WITH_EXPIRED_CERT
);
await errorPageLoaded;
Assert.ok(true, "Error page is loaded");
BrowserTestUtils.removeTab(tabInDefaultUserContext);
BrowserTestUtils.removeTab(tabInUserContext);
ContextualIdentityService.remove(userContextId);
info("Reenable security checks");
certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
false
);
}
);
add_task(
async function test_reset_disable_all_security_checks_for_user_context() {
const certOverrideService = Cc[
"@mozilla.org/security/certoverride;1"
].getService(Ci.nsICertOverrideService);
const userContext = ContextualIdentityService.create("test_name");
const { userContextId } = userContext;
const tabInUserContext = BrowserTestUtils.addTab(gBrowser, PAGE_URL, {
userContextId,
});
const browserInUserContext = tabInUserContext.linkedBrowser;
info("Loading and waiting for the cert error in user context");
let errorPageLoaded =
BrowserTestUtils.waitForErrorPage(browserInUserContext);
BrowserTestUtils.startLoadingURIString(
browserInUserContext,
PAGE_WITH_EXPIRED_CERT
);
await errorPageLoaded;
Assert.ok(true, "Error page is loaded");
info("Disable security checks for user context");
certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyDataForUserContext(
userContextId,
true
);
let loadedPromise = BrowserTestUtils.browserLoaded(browserInUserContext);
BrowserTestUtils.startLoadingURIString(
browserInUserContext,
PAGE_WITH_EXPIRED_CERT
);
await loadedPromise;
Assert.ok(true, "Normal page is loaded in user context");
info("Reset disable security checks for user context");
certOverrideService.resetDisableAllSecurityChecksAndLetAttackersInterceptMyDataForUserContext(
userContextId
);
errorPageLoaded = BrowserTestUtils.waitForErrorPage(browserInUserContext);
BrowserTestUtils.startLoadingURIString(
browserInUserContext,
PAGE_WITH_EXPIRED_CERT
);
await errorPageLoaded;
Assert.ok(true, "Error page is loaded");
BrowserTestUtils.removeTab(tabInUserContext);
ContextualIdentityService.remove(userContextId);
}
);