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 bool
BasePrincipal::AddonAllowsLoad(nsIURI* aURI, bool aExplicit /* = false */) BasePrincipal::AddonAllowsLoad(nsIURI* aURI, bool aExplicit /* = false */)
{ {
if (Is<ExpandedPrincipal>()) {
return As<ExpandedPrincipal>()->AddonAllowsLoad(aURI, aExplicit);
}
if (auto policy = AddonPolicy()) { if (auto policy = AddonPolicy()) {
return policy->CanAccessURI(aURI, aExplicit); return policy->CanAccessURI(aURI, aExplicit);
} }

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

@ -180,6 +180,17 @@ ExpandedPrincipal::AddonHasPermission(const nsAtom* aPerm)
return false; 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* nsIPrincipal*
ExpandedPrincipal::PrincipalToInherit(nsIURI* aRequestedURI) ExpandedPrincipal::PrincipalToInherit(nsIURI* aRequestedURI)
{ {

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

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

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

@ -6,6 +6,7 @@
#include "PerformanceResourceTiming.h" #include "PerformanceResourceTiming.h"
#include "mozilla/dom/PerformanceResourceTimingBinding.h" #include "mozilla/dom/PerformanceResourceTimingBinding.h"
#include "nsNetUtil.h"
using namespace mozilla::dom; using namespace mozilla::dom;
@ -31,6 +32,11 @@ PerformanceResourceTiming::PerformanceResourceTiming(UniquePtr<PerformanceTiming
, mPerformance(aPerformance) , mPerformance(aPerformance)
{ {
MOZ_ASSERT(aPerformance, "Parent performance object should be provided"); 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() PerformanceResourceTiming::~PerformanceResourceTiming()
@ -80,3 +86,35 @@ PerformanceResourceTiming::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSize
? mTimingData->NextHopProtocol().SizeOfExcludingThisIfUnshared(aMallocSizeOf) ? mTimingData->NextHopProtocol().SizeOfExcludingThisIfUnshared(aMallocSizeOf)
: 0); : 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; : 0;
} }
DOMHighResTimeStamp RedirectStart() const { DOMHighResTimeStamp RedirectStart(Maybe<nsIPrincipal*>& aSubjectPrincipal) const {
// We have to check if all the redirect URIs had the same origin (since // We have to check if all the redirect URIs had the same origin (since
// there is no check in RedirectEndHighRes()) // there is no check in RedirectStartHighRes())
return mTimingData && mTimingData->ShouldReportCrossOriginRedirect() return ReportRedirectForCaller(aSubjectPrincipal)
? mTimingData->RedirectStartHighRes(mPerformance) ? mTimingData->RedirectStartHighRes(mPerformance)
: 0; : 0;
} }
DOMHighResTimeStamp RedirectEnd() const { DOMHighResTimeStamp RedirectEnd(Maybe<nsIPrincipal*>& aSubjectPrincipal) const {
// We have to check if all the redirect URIs had the same origin (since // We have to check if all the redirect URIs had the same origin (since
// there is no check in RedirectEndHighRes()) // there is no check in RedirectEndHighRes())
return mTimingData && mTimingData->ShouldReportCrossOriginRedirect() return ReportRedirectForCaller(aSubjectPrincipal)
? mTimingData->RedirectEndHighRes(mPerformance) ? mTimingData->RedirectEndHighRes(mPerformance)
: 0; : 0;
} }
DOMHighResTimeStamp DomainLookupStart() const { DOMHighResTimeStamp DomainLookupStart(Maybe<nsIPrincipal*>& aSubjectPrincipal) const {
return mTimingData && mTimingData->TimingAllowed() return TimingAllowedForCaller(aSubjectPrincipal)
? mTimingData->DomainLookupStartHighRes(mPerformance) ? mTimingData->DomainLookupStartHighRes(mPerformance)
: 0; : 0;
} }
DOMHighResTimeStamp DomainLookupEnd() const { DOMHighResTimeStamp DomainLookupEnd(Maybe<nsIPrincipal*>& aSubjectPrincipal) const {
return mTimingData && mTimingData->TimingAllowed() return TimingAllowedForCaller(aSubjectPrincipal)
? mTimingData->DomainLookupEndHighRes(mPerformance) ? mTimingData->DomainLookupEndHighRes(mPerformance)
: 0; : 0;
} }
DOMHighResTimeStamp ConnectStart() const { DOMHighResTimeStamp ConnectStart(Maybe<nsIPrincipal*>& aSubjectPrincipal) const {
return mTimingData && mTimingData->TimingAllowed() return TimingAllowedForCaller(aSubjectPrincipal)
? mTimingData->ConnectStartHighRes(mPerformance) ? mTimingData->ConnectStartHighRes(mPerformance)
: 0; : 0;
} }
DOMHighResTimeStamp ConnectEnd() const { DOMHighResTimeStamp ConnectEnd(Maybe<nsIPrincipal*>& aSubjectPrincipal) const {
return mTimingData && mTimingData->TimingAllowed() return TimingAllowedForCaller(aSubjectPrincipal)
? mTimingData->ConnectEndHighRes(mPerformance) ? mTimingData->ConnectEndHighRes(mPerformance)
: 0; : 0;
} }
DOMHighResTimeStamp RequestStart() const { DOMHighResTimeStamp RequestStart(Maybe<nsIPrincipal*>& aSubjectPrincipal) const {
return mTimingData && mTimingData->TimingAllowed() return TimingAllowedForCaller(aSubjectPrincipal)
? mTimingData->RequestStartHighRes(mPerformance) ? mTimingData->RequestStartHighRes(mPerformance)
: 0; : 0;
} }
DOMHighResTimeStamp ResponseStart() const { DOMHighResTimeStamp ResponseStart(Maybe<nsIPrincipal*>& aSubjectPrincipal) const {
return mTimingData && mTimingData->TimingAllowed() return TimingAllowedForCaller(aSubjectPrincipal)
? mTimingData->ResponseStartHighRes(mPerformance) ? mTimingData->ResponseStartHighRes(mPerformance)
: 0; : 0;
} }
@ -128,10 +128,10 @@ public:
: 0; : 0;
} }
DOMHighResTimeStamp SecureConnectionStart() const DOMHighResTimeStamp SecureConnectionStart(Maybe<nsIPrincipal*>& aSubjectPrincipal) const
{ {
return mTimingData && mTimingData->TimingAllowed() return TimingAllowedForCaller(aSubjectPrincipal)
? mTimingData->SecureConnectionStartHighRes(mPerformance) ? mTimingData->SecureConnectionStartHighRes(mPerformance)
: 0; : 0;
} }
@ -140,19 +140,25 @@ public:
return this; 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 size_t
@ -164,9 +170,21 @@ protected:
size_t size_t
SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override; 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; nsString mInitiatorType;
UniquePtr<PerformanceTimingData> mTimingData; UniquePtr<PerformanceTimingData> mTimingData;
RefPtr<Performance> mPerformance; RefPtr<Performance> mPerformance;
// The same initial requested URI as the `name` attribute.
nsCOMPtr<nsIURI> mOriginalURI;
}; };
} // namespace dom } // namespace dom

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

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

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

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