Bug 851586, r=bz

--HG--
extra : rebase_source : 4144764238b0f38f1457358b1c9f61bc4d347424
This commit is contained in:
Gavin Sharp 2013-03-19 12:23:43 +01:00
parent 9bde498c5b
commit decd2dd5c1
8 changed files with 78 additions and 57 deletions

View File

@ -17,9 +17,7 @@ NS_IMPL_ISUPPORTS1(AboutRedirector, nsIAboutModule)
struct RedirEntry {
const char* id;
const char* url;
uint32_t flags; // See nsIAboutModule. The URI_SAFE_FOR_UNTRUSTED_CONTENT
// flag does double duty here -- if it's not set, we don't
// drop chrome privileges.
uint32_t flags;
};
/*
@ -128,28 +126,6 @@ AboutRedirector::NewChannel(nsIURI *aURI, nsIChannel **result)
tempChannel->SetOriginalURI(aURI);
// Keep the page from getting unnecessary privileges unless it needs them
if (kRedirMap[i].flags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) {
if (path.EqualsLiteral("feeds")) {
nsCOMPtr<nsIScriptSecurityManager> securityManager =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPrincipal> principal;
rv = securityManager->GetNoAppCodebasePrincipal(aURI, getter_AddRefs(principal));
NS_ENSURE_SUCCESS(rv, rv);
rv = tempChannel->SetOwner(principal);
}
else {
// Setting the owner to null means that we'll go through the normal
// path in GetChannelPrincipal and create a codebase principal based
// on the channel's originalURI
rv = tempChannel->SetOwner(nullptr);
NS_ENSURE_SUCCESS(rv, rv);
}
}
NS_ADDREF(*result = tempChannel);
return rv;
}

View File

@ -5,6 +5,7 @@
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/debug.js");
Components.utils.import("resource://gre/modules/Services.jsm");
const Cc = Components.classes;
const Ci = Components.interfaces;
@ -23,8 +24,6 @@ const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
const TYPE_ANY = "*/*";
const FEEDHANDLER_URI = "about:feeds";
const PREF_SELECTED_APP = "browser.feeds.handlers.application";
const PREF_SELECTED_WEB = "browser.feeds.handlers.webservice";
const PREF_SELECTED_ACTION = "browser.feeds.handler";
@ -246,12 +245,14 @@ FeedConverter.prototype = {
feedService.addFeedResult(result);
// Now load the actual XUL document.
var chromeURI = ios.newURI(FEEDHANDLER_URI, null, null);
chromeChannel = ios.newChannelFromURI(chromeURI, null);
var aboutFeedsURI = ios.newURI("about:feeds", null, null);
chromeChannel = ios.newChannelFromURI(aboutFeedsURI, null);
chromeChannel.originalURI = result.uri;
}
else
chromeChannel.owner =
Services.scriptSecurityManager.getNoAppCodebasePrincipal(aboutFeedsURI);
} else {
chromeChannel = ios.newChannelFromURI(result.uri, null);
}
chromeChannel.loadGroup = this._request.loadGroup;
chromeChannel.asyncOpen(this._listener, null);

View File

@ -51,7 +51,6 @@ const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
const URI_BUNDLE = "chrome://browser/locale/feeds/subscribe.properties";
const FEEDHANDLER_URI = "about:feeds";
const PREF_SELECTED_APP = "browser.feeds.handlers.application";
const PREF_SELECTED_WEB = "browser.feeds.handlers.webservice";
@ -1102,7 +1101,7 @@ FeedWriter.prototype = {
var resolvedURI = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService).
newChannel(FEEDHANDLER_URI, null, null).URI;
newChannel("about:feeds", null, null).URI;
if (resolvedURI.equals(chan.URI))
return chan.originalURI;

View File

@ -15,9 +15,7 @@ NS_IMPL_ISUPPORTS1(nsAboutRedirector, nsIAboutModule)
struct RedirEntry {
const char* id;
const char* url;
uint32_t flags; // See nsIAboutModule. The URI_SAFE_FOR_UNTRUSTED_CONTENT
// flag does double duty here -- if it's not set, we don't
// drop chrome privileges.
uint32_t flags;
};
/*
@ -99,18 +97,6 @@ nsAboutRedirector::NewChannel(nsIURI *aURI, nsIChannel **result)
tempChannel->SetOriginalURI(aURI);
// Keep the page from getting unnecessary privileges unless it needs them
if (kRedirMap[i].flags &
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT)
{
// Setting the owner to null means that we'll go through the normal
// path in GetChannelPrincipal and create a codebase principal based
// on the channel's originalURI
rv = tempChannel->SetOwner(nullptr);
if (NS_FAILED(rv))
return rv;
}
NS_ADDREF(*result = tempChannel);
return rv;
}

View File

@ -26,6 +26,13 @@
static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
static NS_DEFINE_CID(kNestedAboutURICID, NS_NESTEDABOUTURI_CID);
static bool IsSafeForUntrustedContent(nsIAboutModule *aModule, nsIURI *aURI) {
uint32_t flags;
nsresult rv = aModule->GetURIFlags(aURI, &flags);
NS_ENSURE_SUCCESS(rv, false);
return (flags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) != 0;
}
////////////////////////////////////////////////////////////////////////////////
NS_IMPL_ISUPPORTS1(nsAboutProtocolHandler, nsIProtocolHandler)
@ -80,13 +87,7 @@ nsAboutProtocolHandler::NewURI(const nsACString &aSpec,
nsCOMPtr<nsIAboutModule> aboutMod;
rv = NS_GetAboutModule(url, getter_AddRefs(aboutMod));
if (NS_SUCCEEDED(rv)) {
// The standard return case
uint32_t flags;
rv = aboutMod->GetURIFlags(url, &flags);
NS_ENSURE_SUCCESS(rv, rv);
isSafe =
((flags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) != 0);
isSafe = IsSafeForUntrustedContent(aboutMod, url);
}
if (isSafe) {
@ -133,6 +134,15 @@ nsAboutProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
// The standard return case:
rv = aboutMod->NewChannel(uri, result);
if (NS_SUCCEEDED(rv)) {
// If this URI is safe for untrusted content, enforce that its
// principal be based on the channel's originalURI by setting the
// owner to null.
// Note: this relies on aboutMod's newChannel implementation
// having set the proper originalURI, which probably isn't ideal.
if (IsSafeForUntrustedContent(aboutMod, uri)) {
(*result)->SetOwner(nullptr);
}
nsRefPtr<nsNestedAboutURI> aboutURI;
nsresult rv2 = uri->QueryInterface(kNestedAboutURICID,
getter_AddRefs(aboutURI));

View File

@ -21,8 +21,11 @@ interface nsIAboutModule : nsISupports
/**
* A flag that indicates whether a URI is safe for untrusted
* content. If it is, web pages and so forth will be allowed to
* link to this about: URI. Otherwise, only chrome will be able
* to link to it.
* link to this about: URI, and the about: protocol handler will
* enforce that the principal of channels created for it be based
* on their originalURI or URI (depending on the channel flags),
* by setting their "owner" to null.
* Otherwise, only chrome will be able to link to it.
*/
const unsigned long URI_SAFE_FOR_UNTRUSTED_CONTENT = (1 << 0);

View File

@ -0,0 +1,45 @@
/* 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/. */
let Ci = Components.interfaces;
let Cc = Components.classes;
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
let unsafeAboutModule = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
newChannel: function (aURI) {
let chan = Services.io.newChannel("about:blank", null, null);
chan.owner = Services.scriptSecurityManager.getSystemPrincipal();
return chan;
},
getURIFlags: function (aURI) {
return Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT;
}
};
let factory = {
createInstance: function(aOuter, aIID) {
if (aOuter)
throw Components.results.NS_ERROR_NO_AGGREGATION;
return unsafeAboutModule.QueryInterface(aIID);
},
lockFactory: function(aLock) {
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
};
function run_test() {
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
let classID = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID();
registrar.registerFactory(classID, "", "@mozilla.org/network/protocol/about;1?what=unsafe", factory);
let aboutUnsafeURI = Services.io.newURI("about:unsafe", null, null);
let aboutUnsafeChan = Services.io.newChannelFromURI(aboutUnsafeURI);
do_check_null(aboutUnsafeChan.owner, "URI_SAFE_FOR_UNTRUSTED_CONTENT channel has no owner");
registrar.unregisterFactory(classID, factory);
}

View File

@ -212,3 +212,4 @@ run-if = hasNode
[test_bug826063.js]
[test_bug812167.js]
[test_tldservice_nextsubdomain.js]
[test_about_protocol.js]