NS_IMETHODIMP nsAboutProtocolHandler::NewURI(const nsACString &aSpec, const char *aCharset, // ignore charset info nsIURI *aBaseURI, nsIURI **result) { *result = nullptr; nsresult rv; // Use a simple URI to parse out some stuff first nsCOMPtr<nsIURI> url = do_CreateInstance(kSimpleURICID, &rv); if (NS_FAILED(rv)) return rv; rv = url->SetSpec(aSpec); if (NS_FAILED(rv)) { return rv; } // Unfortunately, people create random about: URIs that don't correspond to // about: modules... Since those URIs will never open a channel, might as // well consider them unsafe for better perf, and just in case. bool isSafe = false; nsCOMPtr<nsIAboutModule> aboutMod; rv = NS_GetAboutModule(url, getter_AddRefs(aboutMod)); if (NS_SUCCEEDED(rv)) { isSafe = IsSafeForUntrustedContent(aboutMod, url); } if (isSafe) { // We need to indicate that this baby is safe. Use an inner URI that // no one but the security manager will see. Make sure to preserve our // path, in case someone decides to hardcode checks for particular // about: URIs somewhere. nsAutoCString spec; rv = url->GetPath(spec); NS_ENSURE_SUCCESS(rv, rv); spec.Insert("moz-safe-about:", 0); nsCOMPtr<nsIURI> inner; rv = NS_NewURI(getter_AddRefs(inner), spec); NS_ENSURE_SUCCESS(rv, rv); nsSimpleNestedURI* outer = new nsNestedAboutURI(inner, aBaseURI); NS_ENSURE_TRUE(outer, NS_ERROR_OUT_OF_MEMORY); // Take a ref to it in the COMPtr we plan to return url = outer; rv = outer->SetSpec(aSpec); NS_ENSURE_SUCCESS(rv, rv); } // We don't want to allow mutation, since it would allow safe and // unsafe URIs to change into each other... NS_TryToSetImmutable(url); url.swap(*result); return NS_OK; }
// static nsresult IDBFactory::AllowedForWindowInternal(nsPIDOMWindowInner* aWindow, nsIPrincipal** aPrincipal) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aWindow); if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) { return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } nsContentUtils::StorageAccess access = nsContentUtils::StorageAllowedForWindow(aWindow); // the factory callsite records whether the browser is in private browsing. // and thus we don't have to respect that setting here. IndexedDB has no // concept of session-local storage, and thus ignores it. if (access <= nsContentUtils::StorageAccess::eDeny) { return NS_ERROR_DOM_SECURITY_ERR; } nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow); MOZ_ASSERT(sop); nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal(); if (NS_WARN_IF(!principal)) { return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } if (nsContentUtils::IsSystemPrincipal(principal)) { principal.forget(aPrincipal); return NS_OK; } // About URIs shouldn't be able to access IndexedDB unless they have the // nsIAboutModule::ENABLE_INDEXED_DB flag set on them. nsCOMPtr<nsIURI> uri; MOZ_ALWAYS_SUCCEEDS(principal->GetURI(getter_AddRefs(uri))); MOZ_ASSERT(uri); bool isAbout = false; MOZ_ALWAYS_SUCCEEDS(uri->SchemeIs("about", &isAbout)); if (isAbout) { nsCOMPtr<nsIAboutModule> module; if (NS_SUCCEEDED(NS_GetAboutModule(uri, getter_AddRefs(module)))) { uint32_t flags; if (NS_SUCCEEDED(module->GetURIFlags(uri, &flags))) { if (!(flags & nsIAboutModule::ENABLE_INDEXED_DB)) { return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } } else { return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } } else { return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } } principal.forget(aPrincipal); return NS_OK; }
NS_IMETHODIMP nsAboutProtocolHandler::GetFlagsForURI(nsIURI* aURI, uint32_t* aFlags) { // First use the default (which is "unsafe for content"): GetProtocolFlags(aFlags); // Now try to see if this URI overrides the default: nsCOMPtr<nsIAboutModule> aboutMod; nsresult rv = NS_GetAboutModule(aURI, getter_AddRefs(aboutMod)); if (NS_FAILED(rv)) { // Swallow this and just tell the consumer the default: return NS_OK; } uint32_t aboutModuleFlags = 0; rv = aboutMod->GetURIFlags(aURI, &aboutModuleFlags); // This should never happen, so pass back the error: NS_ENSURE_SUCCESS(rv, rv); // If marked as safe, and marked linkable, pass 'safe' flags. if ((aboutModuleFlags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) && (aboutModuleFlags & nsIAboutModule::MAKE_LINKABLE)) { *aFlags = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_ANYONE | URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT; } return NS_OK; }
NS_IMETHODIMP nsAboutProtocolHandler::GetFlagsForURI(nsIURI* aURI, uint32_t* aFlags) { // First use the default (which is "unsafe for content"): GetProtocolFlags(aFlags); // Now try to see if this URI overrides the default: nsCOMPtr<nsIAboutModule> aboutMod; nsresult rv = NS_GetAboutModule(aURI, getter_AddRefs(aboutMod)); if (NS_FAILED(rv)) { // Swallow this and just tell the consumer the default: return NS_OK; } uint32_t aboutModuleFlags = 0; rv = aboutMod->GetURIFlags(aURI, &aboutModuleFlags); // This should never happen, so pass back the error: NS_ENSURE_SUCCESS(rv, rv); // Secure (https) pages can load safe about pages without becoming // mixed content. if (aboutModuleFlags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) { *aFlags |= URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT; // about: pages can only be loaded by unprivileged principals // if they are marked as LINKABLE if (aboutModuleFlags & nsIAboutModule::MAKE_LINKABLE) { // Replace URI_DANGEROUS_TO_LOAD with URI_LOADABLE_BY_ANYONE. *aFlags &= ~URI_DANGEROUS_TO_LOAD; *aFlags |= URI_LOADABLE_BY_ANYONE; } } return NS_OK; }
NS_IMETHODIMP nsAboutProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result) { NS_ENSURE_ARG_POINTER(uri); // about:what you ask? nsCOMPtr<nsIAboutModule> aboutMod; nsresult rv = NS_GetAboutModule(uri, getter_AddRefs(aboutMod)); nsAutoCString path; nsresult rv2 = NS_GetAboutModuleName(uri, path); if (NS_SUCCEEDED(rv2) && path.EqualsLiteral("srcdoc")) { // about:srcdoc is meant to be unresolvable, yet is included in the // about lookup tables so that it can pass security checks when used in // a srcdoc iframe. To ensure that it stays unresolvable, we pretend // that it doesn't exist. rv = NS_ERROR_FACTORY_NOT_REGISTERED; } if (NS_SUCCEEDED(rv)) { // 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)); if (NS_SUCCEEDED(rv2) && aboutURI->GetBaseURI()) { nsCOMPtr<nsIWritablePropertyBag2> writableBag = do_QueryInterface(*result); if (writableBag) { writableBag-> SetPropertyAsInterface(NS_LITERAL_STRING("baseURI"), aboutURI->GetBaseURI()); } } } return rv; } // mumble... if (rv == NS_ERROR_FACTORY_NOT_REGISTERED) { // This looks like an about: we don't know about. Convert // this to an invalid URI error. rv = NS_ERROR_MALFORMED_URI; } return rv; }
NS_IMETHODIMP nsAboutProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result) { NS_ENSURE_ARG_POINTER(uri); // about:what you ask? nsCOMPtr<nsIAboutModule> aboutMod; nsresult rv = NS_GetAboutModule(uri, getter_AddRefs(aboutMod)); if (NS_SUCCEEDED(rv)) { // The standard return case: rv = aboutMod->NewChannel(uri, result); if (NS_SUCCEEDED(rv)) { nsRefPtr<nsNestedAboutURI> aboutURI; nsresult rv2 = uri->QueryInterface(kNestedAboutURICID, getter_AddRefs(aboutURI)); if (NS_SUCCEEDED(rv2) && aboutURI->GetBaseURI()) { nsCOMPtr<nsIWritablePropertyBag2> writableBag = do_QueryInterface(*result); if (writableBag) { writableBag-> SetPropertyAsInterface(NS_LITERAL_STRING("baseURI"), aboutURI->GetBaseURI()); } } } return rv; } // mumble... if (rv == NS_ERROR_FACTORY_NOT_REGISTERED) { // This looks like an about: we don't know about. Convert // this to an invalid URI error. rv = NS_ERROR_MALFORMED_URI; } return rv; }
NS_IMETHODIMP nsAboutProtocolHandler::NewChannel2(nsIURI* uri, nsILoadInfo* aLoadInfo, nsIChannel** result) { NS_ENSURE_ARG_POINTER(uri); // about:what you ask? nsCOMPtr<nsIAboutModule> aboutMod; nsresult rv = NS_GetAboutModule(uri, getter_AddRefs(aboutMod)); nsAutoCString path; nsresult rv2 = NS_GetAboutModuleName(uri, path); if (NS_SUCCEEDED(rv2) && path.EqualsLiteral("srcdoc")) { // about:srcdoc is meant to be unresolvable, yet is included in the // about lookup tables so that it can pass security checks when used in // a srcdoc iframe. To ensure that it stays unresolvable, we pretend // that it doesn't exist. rv = NS_ERROR_FACTORY_NOT_REGISTERED; } if (NS_SUCCEEDED(rv)) { // The standard return case: rv = aboutMod->NewChannel(uri, aLoadInfo, result); if (NS_SUCCEEDED(rv)) { // Not all implementations of nsIAboutModule::NewChannel() // set the LoadInfo on the newly created channel yet, as // an interim solution we set the LoadInfo here if not // available on the channel. Bug 1087720 nsCOMPtr<nsILoadInfo> loadInfo = (*result)->GetLoadInfo(); if (aLoadInfo != loadInfo) { if (loadInfo) { NS_ASSERTION(false, "nsIAboutModule->newChannel(aURI, aLoadInfo) needs to set LoadInfo"); const char16_t* params[] = { u"nsIAboutModule->newChannel(aURI)", u"nsIAboutModule->newChannel(aURI, aLoadInfo)" }; nsContentUtils::ReportToConsole( nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Security by Default"), nullptr, // aDocument nsContentUtils::eNECKO_PROPERTIES, "APIDeprecationWarning", params, mozilla::ArrayLength(params)); } (*result)->SetLoadInfo(aLoadInfo); } // 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); } RefPtr<nsNestedAboutURI> aboutURI; nsresult rv2 = uri->QueryInterface(kNestedAboutURICID, getter_AddRefs(aboutURI)); if (NS_SUCCEEDED(rv2) && aboutURI->GetBaseURI()) { nsCOMPtr<nsIWritablePropertyBag2> writableBag = do_QueryInterface(*result); if (writableBag) { writableBag-> SetPropertyAsInterface(NS_LITERAL_STRING("baseURI"), aboutURI->GetBaseURI()); } } } return rv; } // mumble... if (rv == NS_ERROR_FACTORY_NOT_REGISTERED) { // This looks like an about: we don't know about. Convert // this to an invalid URI error. rv = NS_ERROR_MALFORMED_URI; } return rv; }
// static nsresult IDBFactory::AllowedForWindowInternal(nsPIDOMWindow* aWindow, nsIPrincipal** aPrincipal) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aWindow); MOZ_ASSERT(aWindow->IsInnerWindow()); if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) { return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } nsIDocument* document = aWindow->GetExtantDoc(); if (document->GetSandboxFlags() & SANDBOXED_ORIGIN) { return NS_ERROR_DOM_SECURITY_ERR; } nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow); MOZ_ASSERT(sop); nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal(); if (NS_WARN_IF(!principal)) { return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } if (nsContentUtils::IsSystemPrincipal(principal)) { principal.forget(aPrincipal); return NS_OK; } bool isNullPrincipal; if (NS_WARN_IF(NS_FAILED(principal->GetIsNullPrincipal(&isNullPrincipal))) || isNullPrincipal) { return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } // Whitelist about:home, since it doesn't have a base domain it would not // pass the ThirdPartyUtil check, though it should be able to use indexedDB. bool skipThirdPartyCheck = false; nsCOMPtr<nsIURI> uri; MOZ_ALWAYS_TRUE(NS_SUCCEEDED(principal->GetURI(getter_AddRefs(uri)))); bool isAbout; MOZ_ALWAYS_TRUE(NS_SUCCEEDED(uri->SchemeIs("about", &isAbout))); if (isAbout) { nsCOMPtr<nsIAboutModule> module; if (NS_SUCCEEDED(NS_GetAboutModule(uri, getter_AddRefs(module)))) { uint32_t flags; if (NS_SUCCEEDED(module->GetURIFlags(uri, &flags))) { skipThirdPartyCheck = flags & nsIAboutModule::ENABLE_INDEXED_DB; } else { NS_WARNING("GetURIFlags failed!"); } } else { NS_WARNING("NS_GetAboutModule failed!"); } } if (!skipThirdPartyCheck) { nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID); MOZ_ASSERT(thirdPartyUtil); bool isThirdParty; if (NS_WARN_IF(NS_FAILED( thirdPartyUtil->IsThirdPartyWindow(aWindow, nullptr, &isThirdParty)))) { return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } if (isThirdParty) { return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } } principal.forget(aPrincipal); return NS_OK; }