author | Tim Huang <tihuang@mozilla.com> |
Fri, 12 Jun 2020 16:31:49 +0000 | |
changeset 535503 | 44e71580890195d163912b96f41ef09e32570ec8 |
parent 535502 | a890be633ec35c79b8c8fe68e8b32ab7c991ff83 |
child 535504 | a2bec965260d58e8f5bd814c179444875d9962cf |
push id | 37501 |
push user | nbeleuzu@mozilla.com |
push date | Sat, 13 Jun 2020 03:21:52 +0000 |
treeherder | mozilla-central@80b6f21783a3 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | baku, nika |
bugs | 1587743 |
milestone | 79.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/docshell/base/WindowContext.cpp +++ b/docshell/base/WindowContext.cpp @@ -161,16 +161,30 @@ bool WindowContext::CanSet(FieldIndex<ID return CheckOnlyOwningProcessCanSet(aSource); } bool WindowContext::CanSet(FieldIndex<IDX_AutoplayPermission>, const uint32_t& aValue, ContentParent* aSource) { return CheckOnlyOwningProcessCanSet(aSource); } +bool WindowContext::CanSet( + FieldIndex<IDX_DelegatedPermissions>, + const PermissionDelegateHandler::DelegatedPermissionList& aValue, + ContentParent* aSource) { + return CheckOnlyOwningProcessCanSet(aSource); +} + +bool WindowContext::CanSet( + FieldIndex<IDX_DelegatedExactHostMatchPermissions>, + const PermissionDelegateHandler::DelegatedPermissionList& aValue, + ContentParent* aSource) { + return CheckOnlyOwningProcessCanSet(aSource); +} + void WindowContext::CreateFromIPC(IPCInitializer&& aInit) { MOZ_RELEASE_ASSERT(XRE_IsContentProcess(), "Should be a WindowGlobalParent in the parent"); RefPtr<BrowsingContext> bc = BrowsingContext::Get(aInit.mBrowsingContextId); MOZ_RELEASE_ASSERT(bc); if (bc->IsDiscarded()) {
--- a/docshell/base/WindowContext.h +++ b/docshell/base/WindowContext.h @@ -2,16 +2,17 @@ /* 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/. */ #ifndef mozilla_dom_WindowContext_h #define mozilla_dom_WindowContext_h +#include "mozilla/PermissionDelegateHandler.h" #include "mozilla/Span.h" #include "mozilla/dom/MaybeDiscarded.h" #include "mozilla/dom/SyncedContext.h" namespace mozilla { namespace dom { class WindowGlobalParent; @@ -40,17 +41,21 @@ class BrowsingContextGroup; FIELD(IsSecureContext, bool) \ /* Mixed-Content: If the corresponding document URI is potentially \ * trustworthy, then this flag is true. */ \ FIELD(IsPotentiallyTrustWorthy, bool) \ /* Whether the user has overriden the mixed content blocker to allow \ * mixed content loads to happen */ \ FIELD(AllowMixedContent, bool) \ FIELD(EmbedderPolicy, nsILoadInfo::CrossOriginEmbedderPolicy) \ - FIELD(AutoplayPermission, uint32_t) + FIELD(AutoplayPermission, uint32_t) \ + FIELD(DelegatedPermissions, \ + PermissionDelegateHandler::DelegatedPermissionList) \ + FIELD(DelegatedExactHostMatchPermissions, \ + PermissionDelegateHandler::DelegatedPermissionList) class WindowContext : public nsISupports, public nsWrapperCache { MOZ_DECL_SYNCED_CONTEXT(WindowContext, MOZ_EACH_WC_FIELD) NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WindowContext) public: @@ -156,16 +161,22 @@ class WindowContext : public nsISupports bool CanSet(FieldIndex<IDX_IsSecureContext>, const bool& aIsSecureContext, ContentParent* aSource); bool CanSet(FieldIndex<IDX_AutoplayPermission>, const uint32_t& aValue, ContentParent* aSource); bool CanSet(FieldIndex<IDX_SHEntryHasUserInteraction>, const bool& aSHEntryHasUserInteraction, ContentParent* aSource) { return true; } + bool CanSet(FieldIndex<IDX_DelegatedPermissions>, + const PermissionDelegateHandler::DelegatedPermissionList& aValue, + ContentParent* aSource); + bool CanSet(FieldIndex<IDX_DelegatedExactHostMatchPermissions>, + const PermissionDelegateHandler::DelegatedPermissionList& aValue, + ContentParent* aSource); // Overload `DidSet` to get notifications for a particular field being set. // // You can also overload the variant that gets the old value if you need it. template <size_t I> void DidSet(FieldIndex<I>) {} template <size_t I, typename T> void DidSet(FieldIndex<I>, T&& aOldValue) {}
--- a/dom/base/nsGlobalWindowInner.cpp +++ b/dom/base/nsGlobalWindowInner.cpp @@ -1576,16 +1576,23 @@ void nsGlobalWindowInner::InitDocumentDe ClearDocumentDependentSlots(aCx); if (!mWindowGlobalChild) { mWindowGlobalChild = WindowGlobalChild::Create(this); } UpdateAutoplayPermission(); + RefPtr<PermissionDelegateHandler> permDelegateHandler = + mDoc->GetPermissionDelegateHandler(); + + if (permDelegateHandler) { + permDelegateHandler->PopulateAllDelegatedPermissions(); + } + if (mWindowGlobalChild && GetBrowsingContext()) { GetBrowsingContext()->NotifyResetUserGestureActivation(); } #if defined(MOZ_WIDGET_ANDROID) // When we insert the new document to the window in the top-level browsing // context, we should reset the status of the request which is used for the // previous document. @@ -4959,16 +4966,24 @@ nsresult nsGlobalWindowInner::Observe(ns return NS_OK; } nsAutoCString type; perm->GetType(type); if (type == NS_LITERAL_CSTRING("autoplay-media")) { UpdateAutoplayPermission(); } + + RefPtr<PermissionDelegateHandler> permDelegateHandler = + mDoc->GetPermissionDelegateHandler(); + + if (permDelegateHandler) { + permDelegateHandler->UpdateDelegatedPermission(type); + } + return NS_OK; } if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) { MOZ_ASSERT(!NS_strcmp(aData, u"intl.accept_languages")); // The user preferred languages have changed, we need to fire an event on // Window object and invalidate the cache for navigator.languages. It is
--- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -120,16 +120,17 @@ using mozilla::dom::MediaSessionAction f using mozilla::dom::MediaSessionPlaybackState from "mozilla/dom/MediaSessionIPCUtils.h"; using refcounted class nsDocShellLoadState from "nsDocShellLoadState.h"; using mozilla::dom::ServiceWorkerShutdownState::Progress from "mozilla/dom/ServiceWorkerShutdownState.h"; using mozilla::ContentBlockingNotifier::StorageAccessPermissionGrantedReason from "mozilla/ContentBlockingNotifier.h"; using mozilla::ContentBlockingNotifier::BlockingDecision from "mozilla/ContentBlockingNotifier.h"; using mozilla::ContentBlocking::StorageAccessPromptChoices from "mozilla/ContentBlocking.h"; using JSActorMessageKind from "mozilla/dom/JSActor.h"; using JSActorMessageMeta from "mozilla/dom/PWindowGlobal.h"; +using mozilla::PermissionDelegateHandler::DelegatedPermissionList from "mozilla/PermissionDelegateIPCUtils.h"; union ChromeRegistryItem { ChromePackage; OverrideMapping; SubstitutionMapping; };
--- a/extensions/permissions/PermissionDelegateHandler.cpp +++ b/extensions/permissions/PermissionDelegateHandler.cpp @@ -10,16 +10,17 @@ #include "nsPIDOMWindow.h" #include "nsIPrincipal.h" #include "nsContentPermissionHelper.h" #include "mozilla/BasePrincipal.h" #include "mozilla/StaticPrefs_permissions.h" #include "mozilla/dom/Document.h" #include "mozilla/dom/FeaturePolicyUtils.h" +#include "mozilla/dom/WindowContext.h" #include "mozilla/PermissionManager.h" using namespace mozilla::dom; namespace mozilla { typedef PermissionDelegateHandler::PermissionDelegatePolicy DelegatePolicy; typedef PermissionDelegateHandler::PermissionDelegateInfo DelegateInfo; @@ -39,16 +40,22 @@ static const DelegateInfo sPermissionsMa {"midi", nullptr, DelegatePolicy::eDelegateUseIframeOrigin}, {"storage-access", nullptr, DelegatePolicy::eDelegateUseIframeOrigin}, {"camera", u"camera", DelegatePolicy::eDelegateUseFeaturePolicy}, {"microphone", u"microphone", DelegatePolicy::eDelegateUseFeaturePolicy}, {"screen", u"display-capture", DelegatePolicy::eDelegateUseFeaturePolicy}, {"xr", u"xr-spatial-tracking", DelegatePolicy::eDelegateUseFeaturePolicy}, }; +static_assert(PermissionDelegateHandler::DELEGATED_PERMISSION_COUNT == + (sizeof(sPermissionsMap) / sizeof(DelegateInfo)), + "The PermissionDelegateHandler::DELEGATED_PERMISSION_COUNT must " + "match to the " + "length of sPermissionsMap. Please update it."); + NS_IMPL_CYCLE_COLLECTION(PermissionDelegateHandler) NS_IMPL_CYCLE_COLLECTING_ADDREF(PermissionDelegateHandler) NS_IMPL_CYCLE_COLLECTING_RELEASE(PermissionDelegateHandler) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PermissionDelegateHandler) NS_INTERFACE_MAP_ENTRY(nsIPermissionDelegateHandler) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END @@ -145,23 +152,16 @@ bool PermissionDelegateHandler::Initiali nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(window); if (innerWindow) { mTopLevelPrincipal = innerWindow->GetTopLevelAntiTrackingPrincipal(); } return true; } -static bool IsTopWindowContent(Document* aDocument) { - MOZ_ASSERT(aDocument); - - BrowsingContext* browsingContext = aDocument->GetBrowsingContext(); - return browsingContext && browsingContext->IsTopContent(); -} - bool PermissionDelegateHandler::HasFeaturePolicyAllowed( const DelegateInfo* info) const { if (info->mPolicy != DelegatePolicy::eDelegateUseFeaturePolicy || !info->mFeatureName) { return true; } nsAutoString featureName(info->mFeatureName); @@ -183,17 +183,17 @@ bool PermissionDelegateHandler::HasPermi return false; } if (!StaticPrefs::permissions_delegation_enabled()) { return true; } if (info->mPolicy == DelegatePolicy::ePersistDeniedCrossOrigin && - !IsTopWindowContent(mDocument) && + !mDocument->IsTopLevelContentDocument() && !mPrincipal->Subsumes(mTopLevelPrincipal)) { return false; } return true; } nsresult PermissionDelegateHandler::GetPermission(const nsACString& aType, @@ -219,17 +219,17 @@ nsresult PermissionDelegateHandler::GetP : &nsIPermissionManager::TestPermissionFromPrincipal; if (!StaticPrefs::permissions_delegation_enabled()) { return (mPermissionManager->*testPermission)(mPrincipal, aType, aPermission); } if (info->mPolicy == DelegatePolicy::ePersistDeniedCrossOrigin && - !IsTopWindowContent(mDocument) && + !mDocument->IsTopLevelContentDocument() && !mPrincipal->Subsumes(mTopLevelPrincipal)) { *aPermission = nsIPermissionManager::DENY_ACTION; return NS_OK; } nsIPrincipal* principal = mPrincipal; if (mTopLevelPrincipal && (info->mPolicy == DelegatePolicy::eDelegateUseTopOrigin || @@ -241,9 +241,113 @@ nsresult PermissionDelegateHandler::GetP return (mPermissionManager->*testPermission)(principal, aType, aPermission); } nsresult PermissionDelegateHandler::GetPermissionForPermissionsAPI( const nsACString& aType, uint32_t* aPermission) { return GetPermission(aType, aPermission, false); } +void PermissionDelegateHandler::PopulateAllDelegatedPermissions() { + MOZ_ASSERT(mDocument); + MOZ_ASSERT(mPermissionManager); + + // We only populate the delegated permissions for the top-level content. + if (!mDocument->IsTopLevelContentDocument()) { + return; + } + + RefPtr<WindowContext> wc = mDocument->GetWindowContext(); + NS_ENSURE_TRUE_VOID(wc); + + DelegatedPermissionList list; + DelegatedPermissionList exactHostMatchList; + + for (const auto& perm : sPermissionsMap) { + size_t idx = std::distance(sPermissionsMap, &perm); + + nsDependentCString type(perm.mPermissionName); + // Populate the permission. + uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION; + Unused << mPermissionManager->TestPermissionFromPrincipal(mPrincipal, type, + &permission); + list.mPermissions[idx] = permission; + + // Populate the exact-host-match permission. + permission = nsIPermissionManager::UNKNOWN_ACTION; + Unused << mPermissionManager->TestExactPermissionFromPrincipal( + mPrincipal, type, &permission); + exactHostMatchList.mPermissions[idx] = permission; + } + + WindowContext::Transaction txn; + txn.SetDelegatedPermissions(list); + txn.SetDelegatedExactHostMatchPermissions(exactHostMatchList); + txn.Commit(wc); +} + +void PermissionDelegateHandler::UpdateDelegatedPermission( + const nsACString& aType) { + MOZ_ASSERT(mDocument); + MOZ_ASSERT(mPermissionManager); + + // We only update the delegated permission for the top-level content. + if (!mDocument->IsTopLevelContentDocument()) { + return; + } + + RefPtr<WindowContext> wc = mDocument->GetWindowContext(); + NS_ENSURE_TRUE_VOID(wc); + + const DelegateInfo* info = + GetPermissionDelegateInfo(NS_ConvertUTF8toUTF16(aType)); + NS_ENSURE_TRUE_VOID(info); + size_t idx = std::distance(sPermissionsMap, info); + + WindowContext::Transaction txn; + bool changed = false; + DelegatedPermissionList list = wc->GetDelegatedPermissions(); + + if (UpdateDelegatePermissionInternal( + list, aType, idx, + &nsIPermissionManager::TestPermissionFromPrincipal)) { + txn.SetDelegatedPermissions(list); + changed = true; + } + + DelegatedPermissionList exactHostMatchList = + wc->GetDelegatedExactHostMatchPermissions(); + + if (UpdateDelegatePermissionInternal( + exactHostMatchList, aType, idx, + &nsIPermissionManager::TestExactPermissionFromPrincipal)) { + txn.SetDelegatedExactHostMatchPermissions(exactHostMatchList); + changed = true; + } + + // We only commit if there is any change of permissions. + if (changed) { + txn.Commit(wc); + } +} + +bool PermissionDelegateHandler::UpdateDelegatePermissionInternal( + PermissionDelegateHandler::DelegatedPermissionList& aList, + const nsACString& aType, size_t aIdx, + nsresult (NS_STDCALL nsIPermissionManager::*aTestFunc)(nsIPrincipal*, + const nsACString&, + uint32_t*)) { + MOZ_ASSERT(aTestFunc); + MOZ_ASSERT(mPermissionManager); + MOZ_ASSERT(mPrincipal); + + uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION; + Unused << (mPermissionManager->*aTestFunc)(mPrincipal, aType, &permission); + + if (aList.mPermissions[aIdx] != permission) { + aList.mPermissions[aIdx] = permission; + return true; + } + + return false; +} + } // namespace mozilla
--- a/extensions/permissions/PermissionDelegateHandler.h +++ b/extensions/permissions/PermissionDelegateHandler.h @@ -21,40 +21,52 @@ * access to geolocation, and the iframe has been granted access to geolocation * by Feature Policy, a request from the cross-origin iframe would trigger a * prompt using of the top-level origin. */ #ifndef mozilla_PermissionDelegateHandler_h #define mozilla_PermissionDelegateHandler_h +#include "mozilla/Array.h" #include "nsCycleCollectionParticipant.h" #include "nsISupports.h" #include "nsIPermissionDelegateHandler.h" #include "nsIPermissionManager.h" #include "nsCOMPtr.h" class nsIPrincipal; class nsIContentPermissionRequest; namespace mozilla { namespace dom { class Document; -} +class WindowContext; +} // namespace dom class PermissionDelegateHandler final : public nsIPermissionDelegateHandler { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS(PermissionDelegateHandler) NS_DECL_NSIPERMISSIONDELEGATEHANDLER explicit PermissionDelegateHandler() = default; explicit PermissionDelegateHandler(mozilla::dom::Document* aDocument); + static constexpr size_t DELEGATED_PERMISSION_COUNT = 11; + + typedef struct DelegatedPermissionList { + Array<uint32_t, DELEGATED_PERMISSION_COUNT> mPermissions; + + bool operator==(const DelegatedPermissionList& aOther) const { + return mPermissions == aOther.mPermissions; + } + } DelegatedPermissionList; + bool Initialize(); /* * Indicates if we has the right to make permission request with aType */ bool HasPermissionDelegated(const nsACString& aType); /* @@ -139,28 +151,51 @@ class PermissionDelegateHandler final : * @param aRequest The request which the principal is get from. * @param aResult out argument which will be a principal that we * will return from this function. */ static nsresult GetDelegatePrincipal(const nsACString& aType, nsIContentPermissionRequest* aRequest, nsIPrincipal** aResult); + /** + * Populate all delegated permissions to the WindowContext of the associated + * document. We only populate the permissions for the top-level content. + */ + void PopulateAllDelegatedPermissions(); + + /** + * Update the given delegated permission to the WindowContext. We only + * update it for the top-level content. + */ + void UpdateDelegatedPermission(const nsACString& aType); + private: ~PermissionDelegateHandler() = default; /* * Check whether the permission is blocked by FeaturePolicy directive. * Default allowlist for a featureName of permission used in permissions * delegate should be set to eSelf, to ensure that permission is denied by * default and only have the opportunity to request permission with allow * attribute. */ bool HasFeaturePolicyAllowed(const PermissionDelegateInfo* info) const; + /** + * A helper function to test the permission and set the result to the given + * list. It will return true if the permission is changed, otherwise false. + */ + bool UpdateDelegatePermissionInternal( + PermissionDelegateHandler::DelegatedPermissionList& aList, + const nsACString& aType, size_t aIdx, + nsresult (NS_STDCALL nsIPermissionManager::*aTestFunc)(nsIPrincipal*, + const nsACString&, + uint32_t*)); + // A weak pointer to our document. Nulled out by DropDocumentReference. mozilla::dom::Document* mDocument; nsCOMPtr<nsIPrincipal> mPrincipal; nsCOMPtr<nsIPrincipal> mTopLevelPrincipal; RefPtr<nsIPermissionManager> mPermissionManager; };
new file mode 100644 --- /dev/null +++ b/extensions/permissions/PermissionDelegateIPCUtils.h @@ -0,0 +1,41 @@ +/* -*- 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/. */ + +#ifndef mozilla_permissiondelegateipcutils_h +#define mozilla_permissiondelegateipcutils_h + +#include "ipc/IPCMessageUtils.h" + +#include "mozilla/PermissionDelegateHandler.h" + +namespace IPC { + +template <> +struct ParamTraits< + mozilla::PermissionDelegateHandler::DelegatedPermissionList> { + typedef mozilla::PermissionDelegateHandler::DelegatedPermissionList paramType; + + static void Write(Message* aMsg, const paramType& aParam) { + for (auto& permission : aParam.mPermissions) { + WriteParam(aMsg, permission); + } + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + for (auto& permission : aResult->mPermissions) { + if (!ReadParam(aMsg, aIter, &permission)) { + return false; + } + } + + return true; + } +}; + +} // namespace IPC + +#endif // mozilla_permissiondelegateipcutils_h
--- a/extensions/permissions/moz.build +++ b/extensions/permissions/moz.build @@ -8,16 +8,17 @@ TEST_DIRS += ['test'] TESTING_JS_MODULES += [ 'test/PermissionTestUtils.jsm', ] EXPORTS.mozilla += [ 'Permission.h', 'PermissionDelegateHandler.h', + 'PermissionDelegateIPCUtils.h', 'PermissionManager.h', ] UNIFIED_SOURCES += [ 'Permission.cpp', 'PermissionDelegateHandler.cpp', 'PermissionManager.cpp', ]