summaryrefslogtreecommitdiffstats
path: root/ipc/glue/BackgroundUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/glue/BackgroundUtils.cpp')
-rw-r--r--ipc/glue/BackgroundUtils.cpp382
1 files changed, 382 insertions, 0 deletions
diff --git a/ipc/glue/BackgroundUtils.cpp b/ipc/glue/BackgroundUtils.cpp
new file mode 100644
index 000000000..b335f5c23
--- /dev/null
+++ b/ipc/glue/BackgroundUtils.cpp
@@ -0,0 +1,382 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "BackgroundUtils.h"
+
+#include "MainThreadUtils.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/BasePrincipal.h"
+#include "mozilla/ipc/PBackgroundSharedTypes.h"
+#include "mozilla/net/NeckoChannelParams.h"
+#include "nsPrincipal.h"
+#include "nsIScriptSecurityManager.h"
+#include "nsIURI.h"
+#include "nsNetUtil.h"
+#include "mozilla/LoadInfo.h"
+#include "nsNullPrincipal.h"
+#include "nsServiceManagerUtils.h"
+#include "nsString.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace net {
+class OptionalLoadInfoArgs;
+}
+
+using mozilla::BasePrincipal;
+using namespace mozilla::net;
+
+namespace ipc {
+
+already_AddRefed<nsIPrincipal>
+PrincipalInfoToPrincipal(const PrincipalInfo& aPrincipalInfo,
+ nsresult* aOptionalResult)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(aPrincipalInfo.type() != PrincipalInfo::T__None);
+
+ nsresult stackResult;
+ nsresult& rv = aOptionalResult ? *aOptionalResult : stackResult;
+
+ nsCOMPtr<nsIScriptSecurityManager> secMan =
+ do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return nullptr;
+ }
+
+ nsCOMPtr<nsIPrincipal> principal;
+
+ switch (aPrincipalInfo.type()) {
+ case PrincipalInfo::TSystemPrincipalInfo: {
+ rv = secMan->GetSystemPrincipal(getter_AddRefs(principal));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return nullptr;
+ }
+
+ return principal.forget();
+ }
+
+ case PrincipalInfo::TNullPrincipalInfo: {
+ const NullPrincipalInfo& info =
+ aPrincipalInfo.get_NullPrincipalInfo();
+ principal = nsNullPrincipal::Create(info.attrs());
+
+ return principal.forget();
+ }
+
+ case PrincipalInfo::TContentPrincipalInfo: {
+ const ContentPrincipalInfo& info =
+ aPrincipalInfo.get_ContentPrincipalInfo();
+
+ nsCOMPtr<nsIURI> uri;
+ rv = NS_NewURI(getter_AddRefs(uri), info.spec());
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return nullptr;
+ }
+
+ PrincipalOriginAttributes attrs;
+ if (info.attrs().mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
+ attrs = info.attrs();
+ }
+ principal = BasePrincipal::CreateCodebasePrincipal(uri, attrs);
+ rv = principal ? NS_OK : NS_ERROR_FAILURE;
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return nullptr;
+ }
+
+ // When the principal is serialized, the origin is extract from it. This
+ // can fail, and in case, here we will havea Tvoid_t. If we have a string,
+ // it must match with what the_new_principal.getOrigin returns.
+ if (info.originNoSuffix().type() == ContentPrincipalInfoOriginNoSuffix::TnsCString) {
+ nsAutoCString originNoSuffix;
+ rv = principal->GetOriginNoSuffix(originNoSuffix);
+ if (NS_WARN_IF(NS_FAILED(rv)) ||
+ !info.originNoSuffix().get_nsCString().Equals(originNoSuffix)) {
+ MOZ_CRASH("If the origin was in the contentPrincipalInfo, it must be available when deserialized");
+ }
+ }
+
+ return principal.forget();
+ }
+
+ case PrincipalInfo::TExpandedPrincipalInfo: {
+ const ExpandedPrincipalInfo& info = aPrincipalInfo.get_ExpandedPrincipalInfo();
+
+ nsTArray<nsCOMPtr<nsIPrincipal>> whitelist;
+ nsCOMPtr<nsIPrincipal> wlPrincipal;
+
+ for (uint32_t i = 0; i < info.whitelist().Length(); i++) {
+ wlPrincipal = PrincipalInfoToPrincipal(info.whitelist()[i], &rv);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return nullptr;
+ }
+ // append that principal to the whitelist
+ whitelist.AppendElement(wlPrincipal);
+ }
+
+ RefPtr<nsExpandedPrincipal> expandedPrincipal = new nsExpandedPrincipal(whitelist, info.attrs());
+ if (!expandedPrincipal) {
+ NS_WARNING("could not instantiate expanded principal");
+ return nullptr;
+ }
+
+ principal = expandedPrincipal;
+ return principal.forget();
+ }
+
+ default:
+ MOZ_CRASH("Unknown PrincipalInfo type!");
+ }
+
+ MOZ_CRASH("Should never get here!");
+}
+
+nsresult
+PrincipalToPrincipalInfo(nsIPrincipal* aPrincipal,
+ PrincipalInfo* aPrincipalInfo)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(aPrincipal);
+ MOZ_ASSERT(aPrincipalInfo);
+
+ if (aPrincipal->GetIsNullPrincipal()) {
+ *aPrincipalInfo = NullPrincipalInfo(BasePrincipal::Cast(aPrincipal)->OriginAttributesRef());
+ return NS_OK;
+ }
+
+ nsresult rv;
+ nsCOMPtr<nsIScriptSecurityManager> secMan =
+ do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ bool isSystemPrincipal;
+ rv = secMan->IsSystemPrincipal(aPrincipal, &isSystemPrincipal);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ if (isSystemPrincipal) {
+ *aPrincipalInfo = SystemPrincipalInfo();
+ return NS_OK;
+ }
+
+ // might be an expanded principal
+ nsCOMPtr<nsIExpandedPrincipal> expanded =
+ do_QueryInterface(aPrincipal);
+
+ if (expanded) {
+ nsTArray<PrincipalInfo> whitelistInfo;
+ PrincipalInfo info;
+
+ nsTArray< nsCOMPtr<nsIPrincipal> >* whitelist;
+ MOZ_ALWAYS_SUCCEEDS(expanded->GetWhiteList(&whitelist));
+
+ for (uint32_t i = 0; i < whitelist->Length(); i++) {
+ rv = PrincipalToPrincipalInfo((*whitelist)[i], &info);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ // append that spec to the whitelist
+ whitelistInfo.AppendElement(info);
+ }
+
+ *aPrincipalInfo =
+ ExpandedPrincipalInfo(BasePrincipal::Cast(aPrincipal)->OriginAttributesRef(),
+ Move(whitelistInfo));
+ return NS_OK;
+ }
+
+ // must be a content principal
+
+ nsCOMPtr<nsIURI> uri;
+ rv = aPrincipal->GetURI(getter_AddRefs(uri));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ if (NS_WARN_IF(!uri)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ nsCString spec;
+ rv = uri->GetSpec(spec);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ ContentPrincipalInfoOriginNoSuffix infoOriginNoSuffix;
+
+ nsCString originNoSuffix;
+ rv = aPrincipal->GetOriginNoSuffix(originNoSuffix);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ infoOriginNoSuffix = void_t();
+ } else {
+ infoOriginNoSuffix = originNoSuffix;
+ }
+
+ *aPrincipalInfo = ContentPrincipalInfo(BasePrincipal::Cast(aPrincipal)->OriginAttributesRef(),
+ infoOriginNoSuffix, spec);
+ return NS_OK;
+}
+
+nsresult
+LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo,
+ OptionalLoadInfoArgs* aOptionalLoadInfoArgs)
+{
+ if (!aLoadInfo) {
+ // if there is no loadInfo, then there is nothing to serialize
+ *aOptionalLoadInfoArgs = void_t();
+ return NS_OK;
+ }
+
+ nsresult rv = NS_OK;
+ OptionalPrincipalInfo loadingPrincipalInfo = mozilla::void_t();
+ if (aLoadInfo->LoadingPrincipal()) {
+ PrincipalInfo loadingPrincipalInfoTemp;
+ rv = PrincipalToPrincipalInfo(aLoadInfo->LoadingPrincipal(),
+ &loadingPrincipalInfoTemp);
+ NS_ENSURE_SUCCESS(rv, rv);
+ loadingPrincipalInfo = loadingPrincipalInfoTemp;
+ }
+
+ PrincipalInfo triggeringPrincipalInfo;
+ rv = PrincipalToPrincipalInfo(aLoadInfo->TriggeringPrincipal(),
+ &triggeringPrincipalInfo);
+
+ OptionalPrincipalInfo principalToInheritInfo = mozilla::void_t();
+ if (aLoadInfo->PrincipalToInherit()) {
+ PrincipalInfo principalToInheritInfoTemp;
+ rv = PrincipalToPrincipalInfo(aLoadInfo->PrincipalToInherit(),
+ &principalToInheritInfoTemp);
+ NS_ENSURE_SUCCESS(rv, rv);
+ principalToInheritInfo = principalToInheritInfoTemp;
+ }
+
+ nsTArray<PrincipalInfo> redirectChainIncludingInternalRedirects;
+ for (const nsCOMPtr<nsIPrincipal>& principal : aLoadInfo->RedirectChainIncludingInternalRedirects()) {
+ rv = PrincipalToPrincipalInfo(principal, redirectChainIncludingInternalRedirects.AppendElement());
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ nsTArray<PrincipalInfo> redirectChain;
+ for (const nsCOMPtr<nsIPrincipal>& principal : aLoadInfo->RedirectChain()) {
+ rv = PrincipalToPrincipalInfo(principal, redirectChain.AppendElement());
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ *aOptionalLoadInfoArgs =
+ LoadInfoArgs(
+ loadingPrincipalInfo,
+ triggeringPrincipalInfo,
+ principalToInheritInfo,
+ aLoadInfo->GetSecurityFlags(),
+ aLoadInfo->InternalContentPolicyType(),
+ static_cast<uint32_t>(aLoadInfo->GetTainting()),
+ aLoadInfo->GetUpgradeInsecureRequests(),
+ aLoadInfo->GetVerifySignedContent(),
+ aLoadInfo->GetEnforceSRI(),
+ aLoadInfo->GetForceInheritPrincipalDropped(),
+ aLoadInfo->GetInnerWindowID(),
+ aLoadInfo->GetOuterWindowID(),
+ aLoadInfo->GetParentOuterWindowID(),
+ aLoadInfo->GetFrameOuterWindowID(),
+ aLoadInfo->GetEnforceSecurity(),
+ aLoadInfo->GetInitialSecurityCheckDone(),
+ aLoadInfo->GetIsInThirdPartyContext(),
+ aLoadInfo->GetOriginAttributes(),
+ redirectChainIncludingInternalRedirects,
+ redirectChain,
+ aLoadInfo->CorsUnsafeHeaders(),
+ aLoadInfo->GetForcePreflight(),
+ aLoadInfo->GetIsPreflight(),
+ aLoadInfo->GetForceHSTSPriming(),
+ aLoadInfo->GetMixedContentWouldBlock());
+
+ return NS_OK;
+}
+
+nsresult
+LoadInfoArgsToLoadInfo(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs,
+ nsILoadInfo** outLoadInfo)
+{
+ if (aOptionalLoadInfoArgs.type() == OptionalLoadInfoArgs::Tvoid_t) {
+ *outLoadInfo = nullptr;
+ return NS_OK;
+ }
+
+ const LoadInfoArgs& loadInfoArgs =
+ aOptionalLoadInfoArgs.get_LoadInfoArgs();
+
+ nsresult rv = NS_OK;
+ nsCOMPtr<nsIPrincipal> loadingPrincipal;
+ if (loadInfoArgs.requestingPrincipalInfo().type() != OptionalPrincipalInfo::Tvoid_t) {
+ loadingPrincipal = PrincipalInfoToPrincipal(loadInfoArgs.requestingPrincipalInfo(), &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIPrincipal> triggeringPrincipal =
+ PrincipalInfoToPrincipal(loadInfoArgs.triggeringPrincipalInfo(), &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIPrincipal> principalToInherit;
+ if (loadInfoArgs.principalToInheritInfo().type() != OptionalPrincipalInfo::Tvoid_t) {
+ principalToInherit = PrincipalInfoToPrincipal(loadInfoArgs.principalToInheritInfo(), &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ nsTArray<nsCOMPtr<nsIPrincipal>> redirectChainIncludingInternalRedirects;
+ for (const PrincipalInfo& principalInfo : loadInfoArgs.redirectChainIncludingInternalRedirects()) {
+ nsCOMPtr<nsIPrincipal> redirectedPrincipal =
+ PrincipalInfoToPrincipal(principalInfo, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ redirectChainIncludingInternalRedirects.AppendElement(redirectedPrincipal.forget());
+ }
+
+ nsTArray<nsCOMPtr<nsIPrincipal>> redirectChain;
+ for (const PrincipalInfo& principalInfo : loadInfoArgs.redirectChain()) {
+ nsCOMPtr<nsIPrincipal> redirectedPrincipal =
+ PrincipalInfoToPrincipal(principalInfo, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ redirectChain.AppendElement(redirectedPrincipal.forget());
+ }
+
+ nsCOMPtr<nsILoadInfo> loadInfo =
+ new mozilla::LoadInfo(loadingPrincipal,
+ triggeringPrincipal,
+ principalToInherit,
+ loadInfoArgs.securityFlags(),
+ loadInfoArgs.contentPolicyType(),
+ static_cast<LoadTainting>(loadInfoArgs.tainting()),
+ loadInfoArgs.upgradeInsecureRequests(),
+ loadInfoArgs.verifySignedContent(),
+ loadInfoArgs.enforceSRI(),
+ loadInfoArgs.forceInheritPrincipalDropped(),
+ loadInfoArgs.innerWindowID(),
+ loadInfoArgs.outerWindowID(),
+ loadInfoArgs.parentOuterWindowID(),
+ loadInfoArgs.frameOuterWindowID(),
+ loadInfoArgs.enforceSecurity(),
+ loadInfoArgs.initialSecurityCheckDone(),
+ loadInfoArgs.isInThirdPartyContext(),
+ loadInfoArgs.originAttributes(),
+ redirectChainIncludingInternalRedirects,
+ redirectChain,
+ loadInfoArgs.corsUnsafeHeaders(),
+ loadInfoArgs.forcePreflight(),
+ loadInfoArgs.isPreflight(),
+ loadInfoArgs.forceHSTSPriming(),
+ loadInfoArgs.mixedContentWouldBlock()
+ );
+
+ loadInfo.forget(outLoadInfo);
+ return NS_OK;
+}
+
+} // namespace ipc
+} // namespace mozilla