Bug 1362034 - Have addTab() provide the correct triggering principal. r=ckerschb r=Gijs

Reviewers: ckerschb!, Gijs!

Tags: #secure-revision

Bug #: 1362034

Differential Revision: https://phabricator.services.mozilla.com/D2046

--HG--
extra : source : 44b25dea67d2ed079e17057ab619d827e9983400
extra : amend_source : 5742820277e0269b6f5d42b1abd98fd9b228ac4a
extra : histedit_source : 790bd2490333e4d8fea7774d036eafbc2fc329b9
This commit is contained in:
Jonathan Kingston 2018-07-06 15:14:54 +01:00
parent 2f0987a202
commit 9b7fb2f20c
22 changed files with 173 additions and 72 deletions

View File

@ -247,7 +247,12 @@ var CaptivePortalWatcher = {
// If the tab is gone or going, we need to open a new one.
if (!tab || tab.closing || !tab.parentNode) {
tab = gBrowser.addTab(this.canonicalURL, { ownerTab: gBrowser.selectedTab });
tab = gBrowser.addWebTab(this.canonicalURL, {
ownerTab: gBrowser.selectedTab,
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({
userContextId: gBrowser.contentPrincipal.userContextId,
}),
});
this._captivePortalTab = Cu.getWeakReference(tab);
}

View File

@ -308,7 +308,7 @@
accesskey="&keywordfield.accesskey;"
oncommand="AddKeywordForSearchField();"/>
<menuitem id="context-searchselect"
oncommand="BrowserSearch.loadSearchFromContext(this.searchTerms);"/>
oncommand="BrowserSearch.loadSearchFromContext(this.searchTerms, this.principal);"/>
<menuseparator id="context-sep-sendlinktodevice" class="sync-ui-item"
hidden="true"/>
<menu id="context-sendlinktodevice"

View File

@ -538,7 +538,8 @@ const gStoragePressureObserver = {
accessKey: prefStrBundle.getString("spaceAlert.learnMoreButton.accesskey"),
callback(notificationBar, button) {
let learnMoreURL = Services.urlFormatter.formatURLPref("app.support.baseURL") + "storage-permissions";
gBrowser.selectedTab = gBrowser.addTab(learnMoreURL);
// This is a content URL, loaded from trusted UX.
gBrowser.selectedTab = gBrowser.addTrustedTab(learnMoreURL);
}
});
if (usage < USAGE_THRESHOLD_BYTES) {
@ -3971,8 +3972,11 @@ const BrowserSearch = {
* @return engine The search engine used to perform a search, or null if no
* search was performed.
*/
_loadSearch(searchText, useNewTab, purpose) {
_loadSearch(searchText, useNewTab, purpose, triggeringPrincipal) {
let engine;
if (!triggeringPrincipal) {
throw new Error("Required argument triggeringPrincipal missing within _loadSearch");
}
// If the search bar is visible, use the current engine, otherwise, fall
// back to the default engine.
@ -3996,33 +4000,20 @@ const BrowserSearch = {
useNewTab ? "tab" : "current",
{ postData: submission.postData,
inBackground,
relatedToCurrent: true });
relatedToCurrent: true,
triggeringPrincipal });
return engine;
},
/**
* Just like _loadSearch, but preserving an old API.
*
* @return string Name of the search engine used to perform a search or null
* if a search was not performed.
*/
loadSearch: function BrowserSearch_search(searchText, useNewTab, purpose) {
let engine = BrowserSearch._loadSearch(searchText, useNewTab, purpose);
if (!engine) {
return null;
}
return engine.name;
},
/**
* Perform a search initiated from the context menu.
*
* This should only be called from the context menu. See
* BrowserSearch.loadSearch for the preferred API.
*/
loadSearchFromContext(terms) {
let engine = BrowserSearch._loadSearch(terms, true, "contextmenu");
loadSearchFromContext(terms, triggeringPrincipal) {
let engine = BrowserSearch._loadSearch(terms, true, "contextmenu", triggeringPrincipal);
if (engine) {
BrowserSearch.recordSearchInTelemetry(engine, "contextmenu");
}
@ -7097,7 +7088,7 @@ function BrowserOpenAddonsMgr(aView) {
}
function BeginRecordExecution() {
gBrowser.selectedTab = gBrowser.addTab("about:blank", { recordExecution: "*" });
gBrowser.selectedTab = gBrowser.addWebTab("about:blank", { recordExecution: "*" });
}
function SaveRecordedExecution() {
@ -7120,7 +7111,7 @@ function BeginReplayExecution() {
fp.init(window, null, Ci.nsIFilePicker.modeOpen);
fp.open(rv => {
if (rv == Ci.nsIFilePicker.returnOK || rv == Ci.nsIFilePicker.returnReplace) {
gBrowser.selectedTab = gBrowser.addTab(null, { replayExecution: fp.file.path });
gBrowser.selectedTab = gBrowser.addWebTab(null, { replayExecution: fp.file.path });
}
});
}
@ -7389,7 +7380,8 @@ const gAccessibilityServiceIndicator = {
type === "click") {
let a11yServicesSupportURL =
Services.urlFormatter.formatURLPref("accessibility.support.url");
gBrowser.selectedTab = gBrowser.addTab(a11yServicesSupportURL);
// This is a known URL coming from trusted UI
gBrowser.selectedTab = gBrowser.addTrustedTab(a11yServicesSupportURL);
Services.telemetry.scalarSet("a11y.indicator_acted_on", true);
}
},

View File

@ -1502,6 +1502,7 @@ nsContextMenu.prototype = {
// Store searchTerms in context menu item so we know what to search onclick
menuItem.searchTerms = selectedText;
menuItem.principal = this.principal;
// Copied to alert.js' prefillAlertInfo().
// If the JS character after our truncation point is a trail surrogate,

View File

@ -1373,6 +1373,11 @@ window._gBrowser = {
aName = params.name;
}
// all callers of loadOneTab need to pass a valid triggeringPrincipal.
if (!aTriggeringPrincipal) {
throw new Error("Required argument triggeringPrincipal missing within loadOneTab");
}
var bgLoad = (aLoadInBackground != null) ? aLoadInBackground :
Services.prefs.getBoolPref("browser.tabs.loadInBackground");
var owner = bgLoad ? null : this.selectedTab;
@ -2134,6 +2139,30 @@ window._gBrowser = {
tab.dispatchEvent(evt);
},
/**
* Loads a tab with a default null principal unless specified
*/
addWebTab(aURI, params = {}) {
if (!params.triggeringPrincipal) {
params.triggeringPrincipal = Services.scriptSecurityManager.createNullPrincipal({
userContextId: params.userContextId,
});
}
if (Services.scriptSecurityManager.isSystemPrincipal(params.triggeringPrincipal)) {
throw new Error("System principal should never be passed into addWebTab()");
}
return this.addTab(aURI, params);
},
/**
* Must only be used sparingly for content that came from Chrome context
* If in doubt use addWebTab
*/
addTrustedTab(aURI, params = {}) {
params.triggeringPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
return this.addTab(aURI, params);
},
// eslint-disable-next-line complexity
addTab(aURI, {
allowMixedContent,
@ -2169,6 +2198,13 @@ window._gBrowser = {
recordExecution,
replayExecution,
} = {}) {
// all callers of addTab that pass a params object need to pass
// a valid triggeringPrincipal.
if (!triggeringPrincipal) {
throw new Error("Required argument triggeringPrincipal missing within addTab");
}
// if we're adding tabs, we're past interrupt mode, ditch the owner
if (this.selectedTab.owner) {
this.selectedTab.owner = null;
@ -2824,7 +2860,9 @@ window._gBrowser = {
aTab._mouseleave();
if (newTab)
this.addTab(BROWSER_NEW_TAB_URL, { skipAnimation: true });
this.addTrustedTab(BROWSER_NEW_TAB_URL, {
skipAnimation: true,
});
else
TabBarVisibility.update();
@ -3599,7 +3637,7 @@ window._gBrowser = {
// new tab must have the same usercontextid as the old one
params.userContextId = aTab.getAttribute("usercontextid");
}
let newTab = this.addTab("about:blank", params);
let newTab = this.addWebTab("about:blank", params);
let newBrowser = this.getBrowserForTab(newTab);
// Stop the about:blank load.
@ -5276,10 +5314,22 @@ var TabContextMenu = {
});
},
reopenInContainer(event) {
let userContextId = parseInt(event.target.getAttribute("data-usercontextid"));
/* Create a triggering principal that is able to load the new tab
For codebase principals that are about: chrome: or resource: we need system to load them.
Anything other than system principal needs to have the new userContextId.
*/
let triggeringPrincipal = this.contextTab.linkedBrowser.contentPrincipal;
if (triggeringPrincipal.isNullPrincipal) {
triggeringPrincipal = Services.scriptSecurityManager.createNullPrincipal({ userContextId });
} else if (triggeringPrincipal.isCodebasePrincipal) {
triggeringPrincipal = Services.scriptSecurityManager.createCodebasePrincipal(triggeringPrincipal.URI, { userContextId });
}
let newTab = gBrowser.addTab(this.contextTab.linkedBrowser.currentURI.spec, {
userContextId: parseInt(event.target.getAttribute("data-usercontextid")),
userContextId,
pinned: this.contextTab.pinned,
index: this.contextTab._tPos + 1,
triggeringPrincipal,
});
if (gBrowser.selectedTab == this.contextTab) {

View File

@ -212,6 +212,9 @@ function openWebLinkIn(url, where, params) {
if (!params.triggeringPrincipal) {
params.triggeringPrincipal = Services.scriptSecurityManager.createNullPrincipal({});
}
if (Services.scriptSecurityManager.isSystemPrincipal(params.triggeringPrincipal)) {
throw new Error("System principal should never be passed into openWebLinkIn()");
}
openUILinkIn(url, where, params);
}
@ -256,7 +259,8 @@ function openUILinkIn(url, where, aAllowThirdPartyFixup, aPostData, aReferrerURI
if (arguments.length == 3 && typeof arguments[2] == "object") {
params = aAllowThirdPartyFixup;
} else {
}
if (!params || !params.triggeringPrincipal) {
throw new Error("Required argument triggeringPrincipal missing within openUILinkIn");
}

View File

@ -54,7 +54,11 @@ global.tabGetSender = getSender;
extensions.on("uninstalling", (msg, extension) => {
if (extension.uninstallURL) {
let browser = windowTracker.topWindow.gBrowser;
browser.addTab(extension.uninstallURL, {relatedToCurrent: true});
browser.addTab(extension.uninstallURL, {
disallowInheritPrincipal: true,
relatedToCurrent: true,
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({}),
});
}
});

View File

@ -527,18 +527,8 @@ this.tabs = class extends ExtensionAPI {
}
}).then(window => {
let url;
let principal = context.principal;
if (createProperties.url !== null) {
url = context.uri.resolve(createProperties.url);
if (!context.checkLoadURL(url, {dontReportErrors: true})) {
return Promise.reject({message: `Illegal URL: ${url}`});
}
if (createProperties.openInReaderMode) {
url = `about:reader?url=${encodeURIComponent(url)}`;
}
}
if (createProperties.cookieStoreId && !extension.hasPermission("cookies")) {
return Promise.reject({message: `No permission for cookieStoreId: ${createProperties.cookieStoreId}`});
@ -569,6 +559,19 @@ this.tabs = class extends ExtensionAPI {
}
}
if (createProperties.url !== null) {
url = context.uri.resolve(createProperties.url);
if (!context.checkLoadURL(url, {dontReportErrors: true})) {
return Promise.reject({message: `Illegal URL: ${url}`});
}
if (createProperties.openInReaderMode) {
url = `about:reader?url=${encodeURIComponent(url)}`;
}
} else {
url = window.BROWSER_NEW_TAB_URL;
}
// Only set disallowInheritPrincipal on non-discardable urls as it
// will override creating a lazy browser. Setting triggeringPrincipal
// will ensure other cases are handled, but setting it may prevent
@ -578,8 +581,11 @@ this.tabs = class extends ExtensionAPI {
// Make sure things like about:blank and data: URIs never inherit,
// and instead always get a NullPrincipal.
options.disallowInheritPrincipal = true;
} else {
options.triggeringPrincipal = context.principal;
// Falling back to codebase here as about: requires it, however is safe.
principal = Services.scriptSecurityManager.createCodebasePrincipal(Services.io.newURI(url), {
userContextId: options.userContextId,
privateBrowsingId: PrivateBrowsingUtils.isBrowserPrivate(window.gBrowser) ? 1 : 0,
});
}
tabListener.initTabReady();
@ -618,13 +624,14 @@ this.tabs = class extends ExtensionAPI {
return Promise.reject({message: `Title may only be set for discarded tabs.`});
}
let nativeTab = window.gBrowser.addTab(url || window.BROWSER_NEW_TAB_URL, options);
options.triggeringPrincipal = principal;
let nativeTab = window.gBrowser.addTab(url, options);
if (createProperties.discarded) {
SessionStore.setTabState(nativeTab, {
entries: [{
url: url,
title: options.title,
triggeringPrincipal_base64: Utils.serializePrincipal(context.principal),
triggeringPrincipal_base64: Utils.serializePrincipal(principal),
}],
});
}

View File

@ -2355,7 +2355,7 @@ BrowserGlue.prototype = {
let tabs = win.gBrowser.tabs;
tab = tabs[tabs.length - 1];
} else {
tab = win.gBrowser.addTab(URI.uri);
tab = win.gBrowser.addWebTab(URI.uri);
}
tab.setAttribute("attention", true);
return tab;
@ -2435,7 +2435,7 @@ BrowserGlue.prototype = {
let tabs = win.gBrowser.tabs;
tab = tabs[tabs.length - 1];
} else {
tab = win.gBrowser.addTab(url);
tab = win.gBrowser.addWebTab(url);
}
tab.setAttribute("attention", true);
let clickCallback = (subject, topic, data) => {
@ -2468,7 +2468,7 @@ BrowserGlue.prototype = {
if (!win) {
this._openURLInNewWindow(url);
} else {
win.gBrowser.addTab(url);
win.gBrowser.addWebTab(url);
}
};

View File

@ -731,7 +731,7 @@ var gMainPane = {
return;
}
let url = await FxAccounts.config.promiseSignInURI("dev-edition-setup");
let accountsTab = win.gBrowser.addTab(url);
let accountsTab = win.gBrowser.addWebTab(url);
win.gBrowser.selectedTab = accountsTab;
},

View File

@ -2431,9 +2431,12 @@ var SessionStoreInternal = {
// Create a new tab.
let userContextId = aTab.getAttribute("usercontextid");
let newTab = aTab == aWindow.gBrowser.selectedTab ?
aWindow.gBrowser.addTab(null, {relatedToCurrent: true, ownerTab: aTab, userContextId}) :
aWindow.gBrowser.addTab(null, {userContextId});
let tabOptions = {
userContextId,
...(aTab == aWindow.gBrowser.selectedTab ? {relatedToCurrent: true, ownerTab: aTab} : {})
};
let newTab = aWindow.gBrowser.addTrustedTab(null, tabOptions);
// Start the throbber to pretend we're doing something while actually
// waiting for data from the frame script.
@ -2522,7 +2525,7 @@ var SessionStoreInternal = {
// create a new tab
let tabbrowser = aWindow.gBrowser;
let tab = tabbrowser.selectedTab =
tabbrowser.addTab(null, {
tabbrowser.addTrustedTab(null, {
index: pos,
pinned: state.pinned,
userContextId: state.userContextId,
@ -3492,13 +3495,13 @@ var SessionStoreInternal = {
// Setting noInitialLabel is a perf optimization. Rendering tab labels
// would make resizing the tabs more expensive as we're adding them.
// Each tab will get its initial label set in restoreTab.
tab = tabbrowser.addTab(url,
{ createLazyBrowser,
skipAnimation: true,
noInitialLabel: true,
userContextId,
skipBackgroundNotify: true,
bulkOrderedOpen: true });
tab = tabbrowser.addTrustedTab(url,
{ createLazyBrowser,
skipAnimation: true,
noInitialLabel: true,
userContextId,
skipBackgroundNotify: true,
bulkOrderedOpen: true });
if (select) {
let leftoverTab = tabbrowser.selectedTab;

View File

@ -264,7 +264,7 @@ function toggleRowChecked(aIx) {
function restoreSingleTab(aIx, aShifted) {
var tabbrowser = getBrowserWindow().gBrowser;
var newTab = tabbrowser.addTab();
var newTab = tabbrowser.addWebTab();
var item = gTreeData[aIx];
var tabState = gStateObject.windows[item.parent.ix]

View File

@ -40,13 +40,21 @@ var Tabs = {
async applyConfig() {
fiveTabsHelper();
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let tab = browserWindow.gBrowser.addTab(PREFS_TAB);
let tab = browserWindow.gBrowser.addTab(PREFS_TAB, {
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
});
browserWindow.gBrowser.pinTab(tab);
tab = browserWindow.gBrowser.addTab(CUST_TAB);
tab = browserWindow.gBrowser.addTab(CUST_TAB, {
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
});
browserWindow.gBrowser.pinTab(tab);
tab = browserWindow.gBrowser.addTab("about:privatebrowsing");
tab = browserWindow.gBrowser.addTab("about:privatebrowsing", {
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
});
browserWindow.gBrowser.pinTab(tab);
tab = browserWindow.gBrowser.addTab("about:home");
tab = browserWindow.gBrowser.addTab("about:home", {
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
});
browserWindow.gBrowser.pinTab(tab);
browserWindow.gBrowser.selectTabAtIndex(5);
hoverTab(browserWindow.gBrowser.tabs[2]);

View File

@ -285,7 +285,7 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
// Used by browser-sets.inc, command
openAboutDebugging(gBrowser, hash) {
const url = "about:debugging" + (hash ? "#" + hash : "");
gBrowser.selectedTab = gBrowser.addTab(url);
gBrowser.selectedTab = gBrowser.addTrustedTab(url);
},
/**
@ -293,7 +293,7 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
*/
// Used by browser-sets.inc, command
openConnectScreen(gBrowser) {
gBrowser.selectedTab = gBrowser.addTab("chrome://devtools/content/framework/connect/connect.xhtml");
gBrowser.selectedTab = gBrowser.addTrustedTab("chrome://devtools/content/framework/connect/connect.xhtml");
},
/**

View File

@ -33,8 +33,15 @@ function openRequestInTab(url, requestPostData) {
postData.addHeader("Content-Type", "application/x-www-form-urlencoded");
postData.setData(stringStream);
}
win.gBrowser.selectedTab = win.gBrowser.addTab(url, { postData });
const userContextId = win.gBrowser.contentPrincipal.userContextId;
win.gBrowser.selectedTab = win.gBrowser.addWebTab(url, {
// TODO this should be using the original request principal
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({
userContextId,
}),
userContextId,
postData,
});
}
function getInputStreamFromString(data) {

View File

@ -28,7 +28,11 @@ function receiveProfile(profile) {
const browser = win.gBrowser;
Services.focus.activeWindow = win;
const tab = browser.addTab("https://perf-html.io/from-addon");
const tab = browser.addWebTab("https://perf-html.io/from-addon", {
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({
userContextId: browser.contentPrincipal.userContextId,
})
});
browser.selectedTab = tab;
const mm = tab.linkedBrowser.messageManager;
mm.loadFrameScript(

View File

@ -7,6 +7,7 @@
const { Ci } = require("chrome");
const { E10SUtils } = require("resource://gre/modules/E10SUtils.jsm");
const { tunnelToInnerBrowser } = require("./tunnel");
const Services = require("Services");
function debug(msg) {
// console.log(`RDM swap: ${msg}`);
@ -58,7 +59,10 @@ function swapToInnerBrowser({ tab, containerURL, getInnerBrowser }) {
browserWindow.addEventListener("TabOpen", event => {
event.stopImmediatePropagation();
}, { capture: true, once: true });
return gBrowser.addTab(uri, options);
options.triggeringPrincipal = Services.scriptSecurityManager.createNullPrincipal({
userContextId: options.userContextId,
});
return gBrowser.addWebTab(uri, options);
};
// A version of `gBrowser.swapBrowsersAndCloseOther` that absorbs the `TabClose` event.

View File

@ -691,7 +691,7 @@ DevToolsStartup.prototype = {
}
// Set relatedToCurrent: true to open the tab next to the current one.
gBrowser.selectedTab = gBrowser.addTab(url, {relatedToCurrent: true});
gBrowser.selectedTab = gBrowser.addTrustedTab(url, {relatedToCurrent: true});
},
handleConsoleFlag: function(cmdLine) {

View File

@ -950,6 +950,7 @@ nsDocShell::LoadURI(nsIURI* aURI,
uint32_t flags = 0;
if (inheritPrincipal) {
MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(principalToInherit), "Should not inherit SystemPrincipal");
flags |= INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
}

View File

@ -1187,6 +1187,8 @@ var BrowserApp = {
if ("userRequested" in aParams) tab.userRequested = aParams.userRequested;
tab.isSearch = ("isSearch" in aParams) ? aParams.isSearch : false;
}
// Don't fall back to System here Bug 1474619
let triggeringPrincipal = "triggeringPrincipal" in aParams ? aParams.triggeringPrincipal : Services.scriptSecurityManager.getSystemPrincipal();
try {
aBrowser.loadURI(aURI, {
@ -1194,6 +1196,7 @@ var BrowserApp = {
referrerURI,
charset,
postData,
triggeringPrincipal,
});
} catch(e) {
if (tab) {

View File

@ -247,6 +247,7 @@ this.tabs = class extends ExtensionAPI {
}).api(),
async create(createProperties) {
let principal = context.principal;
let window = createProperties.windowId !== null ?
windowTracker.getWindow(createProperties.windowId, context) :
windowTracker.topWindow;
@ -260,6 +261,9 @@ this.tabs = class extends ExtensionAPI {
if (!context.checkLoadURL(url, {dontReportErrors: true})) {
return Promise.reject({message: `Illegal URL: ${url}`});
}
} else {
// Falling back to system here as about:newtab requires it, however is safe.
principal = Services.scriptSecurityManager.getSystemPrincipal();
}
let options = {};
@ -285,6 +289,7 @@ this.tabs = class extends ExtensionAPI {
options.parentId = BrowserApp.selectedTab.id;
tabListener.initTabReady();
options.triggeringPrincipal = principal;
let nativeTab = BrowserApp.addTab(url, options);
if (createProperties.url) {

View File

@ -346,7 +346,10 @@ var Heartbeat = class {
this.options.postAnswerUrl.searchParams.append(key, engagementParams[key]);
}
// Open the engagement URL in a new tab.
this.chromeWindow.gBrowser.selectedTab = this.chromeWindow.gBrowser.addTab(this.options.postAnswerUrl.toString());
let { gBrowser} = this.chromeWindow;
gBrowser.selectedTab = gBrowser.addWebTab(this.options.postAnswerUrl.toString(), {
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({}),
});
}
this.endTimerIfPresent("surveyEndTimer");