Bug 1441336 - Use addon permissions for PerformanceTiming properties r=bz,kmag

We need to side-step existing cross-origin checks in Performance Timing code
when the caller is a web extension content script that otherwise has permission
to access the cross-origin resource.

MozReview-Commit-ID: 8IgtqZgPWgY

--HG--
extra : rebase_source : e8152c5d8ab32096d1ff7f97311c1b43b57c3694
This commit is contained in:
Tomislav Jovanovic 2018-04-04 16:54:26 +02:00
Родитель d06d126e5d
Коммит 9e09943ad5
7 изменённых файлов: 117 добавлений и 29 удалений

Просмотреть файл

@ -464,6 +464,9 @@ BasePrincipal::CloneStrippingUserContextIdAndFirstPartyDomain()
bool
BasePrincipal::AddonAllowsLoad(nsIURI* aURI, bool aExplicit /* = false */)
{
if (Is<ExpandedPrincipal>()) {
return As<ExpandedPrincipal>()->AddonAllowsLoad(aURI, aExplicit);
}
if (auto policy = AddonPolicy()) {
return policy->CanAccessURI(aURI, aExplicit);
}

Просмотреть файл

@ -180,6 +180,17 @@ ExpandedPrincipal::AddonHasPermission(const nsAtom* aPerm)
return false;
}
bool
ExpandedPrincipal::AddonAllowsLoad(nsIURI* aURI, bool aExplicit /* = false */)
{
for (const auto& principal : mPrincipals) {
if (Cast(principal)->AddonAllowsLoad(aURI, aExplicit)) {
return true;
}
}
return false;
}
nsIPrincipal*
ExpandedPrincipal::PrincipalToInherit(nsIURI* aRequestedURI)
{

Просмотреть файл

@ -37,6 +37,8 @@ public:
virtual bool AddonHasPermission(const nsAtom* aPerm) override;
virtual nsresult GetScriptLocation(nsACString &aStr) override;
bool AddonAllowsLoad(nsIURI* aURI, bool aExplicit = false);
// Returns the principal to inherit when this principal requests the given
// URL. See BasePrincipal::PrincipalToInherit.
nsIPrincipal* PrincipalToInherit(nsIURI* aRequestedURI = nullptr);

Просмотреть файл

@ -6,6 +6,7 @@
#include "PerformanceResourceTiming.h"
#include "mozilla/dom/PerformanceResourceTimingBinding.h"
#include "nsNetUtil.h"
using namespace mozilla::dom;
@ -31,6 +32,11 @@ PerformanceResourceTiming::PerformanceResourceTiming(UniquePtr<PerformanceTiming
, mPerformance(aPerformance)
{
MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
if (NS_IsMainThread()) {
// Used to check if an addon content script has access to this timing.
// We don't need it in workers, and ignore mOriginalURI if null.
NS_NewURI(getter_AddRefs(mOriginalURI), aName);
}
}
PerformanceResourceTiming::~PerformanceResourceTiming()
@ -80,3 +86,35 @@ PerformanceResourceTiming::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSize
? mTimingData->NextHopProtocol().SizeOfExcludingThisIfUnshared(aMallocSizeOf)
: 0);
}
bool
PerformanceResourceTiming::TimingAllowedForCaller(Maybe<nsIPrincipal*>& aCaller) const
{
if (!mTimingData) {
return false;
}
if (mTimingData->TimingAllowed()) {
return true;
}
// Check if the addon has permission to access the cross-origin resource.
return mOriginalURI && aCaller.isSome() &&
BasePrincipal::Cast(aCaller.value())->AddonAllowsLoad(mOriginalURI);
}
bool
PerformanceResourceTiming::ReportRedirectForCaller(Maybe<nsIPrincipal*>& aCaller) const
{
if (!mTimingData) {
return false;
}
if (mTimingData->ShouldReportCrossOriginRedirect()) {
return true;
}
// Only report cross-origin redirect if the addon has <all_urls> permission.
return aCaller.isSome() &&
BasePrincipal::Cast(aCaller.value())->AddonHasPermission(nsGkAtoms::all_urlsPermission);
}

Просмотреть файл

@ -70,54 +70,54 @@ public:
: 0;
}
DOMHighResTimeStamp RedirectStart() const {
DOMHighResTimeStamp RedirectStart(Maybe<nsIPrincipal*>& aSubjectPrincipal) const {
// We have to check if all the redirect URIs had the same origin (since
// there is no check in RedirectEndHighRes())
return mTimingData && mTimingData->ShouldReportCrossOriginRedirect()
// there is no check in RedirectStartHighRes())
return ReportRedirectForCaller(aSubjectPrincipal)
? mTimingData->RedirectStartHighRes(mPerformance)
: 0;
}
DOMHighResTimeStamp RedirectEnd() const {
DOMHighResTimeStamp RedirectEnd(Maybe<nsIPrincipal*>& aSubjectPrincipal) const {
// We have to check if all the redirect URIs had the same origin (since
// there is no check in RedirectEndHighRes())
return mTimingData && mTimingData->ShouldReportCrossOriginRedirect()
return ReportRedirectForCaller(aSubjectPrincipal)
? mTimingData->RedirectEndHighRes(mPerformance)
: 0;
}
DOMHighResTimeStamp DomainLookupStart() const {
return mTimingData && mTimingData->TimingAllowed()
DOMHighResTimeStamp DomainLookupStart(Maybe<nsIPrincipal*>& aSubjectPrincipal) const {
return TimingAllowedForCaller(aSubjectPrincipal)
? mTimingData->DomainLookupStartHighRes(mPerformance)
: 0;
}
DOMHighResTimeStamp DomainLookupEnd() const {
return mTimingData && mTimingData->TimingAllowed()
DOMHighResTimeStamp DomainLookupEnd(Maybe<nsIPrincipal*>& aSubjectPrincipal) const {
return TimingAllowedForCaller(aSubjectPrincipal)
? mTimingData->DomainLookupEndHighRes(mPerformance)
: 0;
}
DOMHighResTimeStamp ConnectStart() const {
return mTimingData && mTimingData->TimingAllowed()
DOMHighResTimeStamp ConnectStart(Maybe<nsIPrincipal*>& aSubjectPrincipal) const {
return TimingAllowedForCaller(aSubjectPrincipal)
? mTimingData->ConnectStartHighRes(mPerformance)
: 0;
}
DOMHighResTimeStamp ConnectEnd() const {
return mTimingData && mTimingData->TimingAllowed()
DOMHighResTimeStamp ConnectEnd(Maybe<nsIPrincipal*>& aSubjectPrincipal) const {
return TimingAllowedForCaller(aSubjectPrincipal)
? mTimingData->ConnectEndHighRes(mPerformance)
: 0;
}
DOMHighResTimeStamp RequestStart() const {
return mTimingData && mTimingData->TimingAllowed()
DOMHighResTimeStamp RequestStart(Maybe<nsIPrincipal*>& aSubjectPrincipal) const {
return TimingAllowedForCaller(aSubjectPrincipal)
? mTimingData->RequestStartHighRes(mPerformance)
: 0;
}
DOMHighResTimeStamp ResponseStart() const {
return mTimingData && mTimingData->TimingAllowed()
DOMHighResTimeStamp ResponseStart(Maybe<nsIPrincipal*>& aSubjectPrincipal) const {
return TimingAllowedForCaller(aSubjectPrincipal)
? mTimingData->ResponseStartHighRes(mPerformance)
: 0;
}
@ -128,10 +128,10 @@ public:
: 0;
}
DOMHighResTimeStamp SecureConnectionStart() const
DOMHighResTimeStamp SecureConnectionStart(Maybe<nsIPrincipal*>& aSubjectPrincipal) const
{
return mTimingData && mTimingData->TimingAllowed()
? mTimingData->SecureConnectionStartHighRes(mPerformance)
return TimingAllowedForCaller(aSubjectPrincipal)
? mTimingData->SecureConnectionStartHighRes(mPerformance)
: 0;
}
@ -140,19 +140,25 @@ public:
return this;
}
uint64_t TransferSize() const
uint64_t TransferSize(Maybe<nsIPrincipal*>& aSubjectPrincipal) const
{
return mTimingData ? mTimingData->TransferSize() : 0;
return TimingAllowedForCaller(aSubjectPrincipal)
? mTimingData->TransferSize()
: 0;
}
uint64_t EncodedBodySize() const
uint64_t EncodedBodySize(Maybe<nsIPrincipal*>& aSubjectPrincipal) const
{
return mTimingData ? mTimingData->EncodedBodySize() : 0;
return TimingAllowedForCaller(aSubjectPrincipal)
? mTimingData->EncodedBodySize()
: 0;
}
uint64_t DecodedBodySize() const
uint64_t DecodedBodySize(Maybe<nsIPrincipal*>& aSubjectPrincipal) const
{
return mTimingData ? mTimingData->DecodedBodySize() : 0;
return TimingAllowedForCaller(aSubjectPrincipal)
? mTimingData->DecodedBodySize()
: 0;
}
size_t
@ -164,9 +170,21 @@ protected:
size_t
SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
// Check if caller has access to cross-origin timings, either by the rules
// from the spec, or based on addon permissions.
bool
TimingAllowedForCaller(Maybe<nsIPrincipal*>& aCaller) const;
// Check if cross-origin redirects should be reported to the caller.
bool
ReportRedirectForCaller(Maybe<nsIPrincipal*>& aCaller) const;
nsString mInitiatorType;
UniquePtr<PerformanceTimingData> mTimingData;
RefPtr<Performance> mPerformance;
// The same initial requested URI as the `name` attribute.
nsCOMPtr<nsIURI> mOriginalURI;
};
} // namespace dom

Просмотреть файл

@ -54,17 +54,17 @@ public:
uint64_t TransferSize() const
{
return mTimingAllowed ? mTransferSize : 0;
return mTransferSize;
}
uint64_t EncodedBodySize() const
{
return mTimingAllowed ? mEncodedBodySize : 0;
return mEncodedBodySize;
}
uint64_t DecodedBodySize() const
{
return mTimingAllowed ? mDecodedBodySize : 0;
return mDecodedBodySize;
}
/**

Просмотреть файл

@ -17,20 +17,36 @@ interface PerformanceResourceTiming : PerformanceEntry
readonly attribute DOMString nextHopProtocol;
readonly attribute DOMHighResTimeStamp workerStart;
[NeedsSubjectPrincipal]
readonly attribute DOMHighResTimeStamp redirectStart;
[NeedsSubjectPrincipal]
readonly attribute DOMHighResTimeStamp redirectEnd;
readonly attribute DOMHighResTimeStamp fetchStart;
[NeedsSubjectPrincipal]
readonly attribute DOMHighResTimeStamp domainLookupStart;
[NeedsSubjectPrincipal]
readonly attribute DOMHighResTimeStamp domainLookupEnd;
[NeedsSubjectPrincipal]
readonly attribute DOMHighResTimeStamp connectStart;
[NeedsSubjectPrincipal]
readonly attribute DOMHighResTimeStamp connectEnd;
[NeedsSubjectPrincipal]
readonly attribute DOMHighResTimeStamp secureConnectionStart;
[NeedsSubjectPrincipal]
readonly attribute DOMHighResTimeStamp requestStart;
[NeedsSubjectPrincipal]
readonly attribute DOMHighResTimeStamp responseStart;
readonly attribute DOMHighResTimeStamp responseEnd;
[NeedsSubjectPrincipal]
readonly attribute unsigned long long transferSize;
[NeedsSubjectPrincipal]
readonly attribute unsigned long long encodedBodySize;
[NeedsSubjectPrincipal]
readonly attribute unsigned long long decodedBodySize;
jsonifier;