Bug 1851816: Pass PBM Status into RFPIsEnabledFor r=timhuang

Differential Revision: https://phabricator.services.mozilla.com/D192501
This commit is contained in:
Tom Ritter 2023-12-18 18:39:33 +00:00
parent ebf3d44836
commit 68cae289a0
12 changed files with 123 additions and 39 deletions

View file

@ -288,6 +288,10 @@ interface nsIScriptSecurityManager : nsISupports
const unsigned long DEFAULT_USER_CONTEXT_ID = 0;
/**
* The constant the indicates when mPrivateBrowsingId is _not_ in PBM.
* In other words, zero indicates Normal Browsing, and non-zero indicates PBM
*/
const unsigned long DEFAULT_PRIVATE_BROWSING_ID = 0;
/**

View file

@ -61,6 +61,7 @@
#include "mozJSModuleLoader.h"
#include "mozilla/ProfilerLabels.h"
#include "mozilla/ProfilerMarkers.h"
#include "nsDocShell.h"
#include "nsIException.h"
#include "VsyncSource.h"
@ -1895,13 +1896,28 @@ bool ChromeUtils::ShouldResistFingerprinting(
MOZ_CRASH("Unhandled JSRFPTarget enum value");
}
bool isPBM = false;
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
if (global) {
nsPIDOMWindowInner* win = global->GetAsInnerWindow();
if (win) {
nsIDocShell* docshell = win->GetDocShell();
if (docshell) {
nsDocShell::Cast(docshell)->GetUsePrivateBrowsing(&isPBM);
}
}
}
Maybe<RFPTarget> overriddenFingerprintingSettings;
if (!aOverriddenFingerprintingSettings.IsNull()) {
overriddenFingerprintingSettings.emplace(
RFPTarget(aOverriddenFingerprintingSettings.Value()));
}
return nsRFPService::IsRFPEnabledFor(target,
// This global object appears to be the global window, not for individual
// sites so to exempt individual sites (instead of just PBM/Not-PBM windows)
// more work would be needed to get the correct context.
return nsRFPService::IsRFPEnabledFor(isPBM, target,
overriddenFingerprintingSettings);
}

View file

@ -2820,6 +2820,8 @@ void Document::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) {
nsCOMPtr<nsIPrincipal> principal;
nsCOMPtr<nsIPrincipal> partitionedPrincipal;
if (aChannel) {
mIsInPrivateBrowsing = NS_UsePrivateBrowsing(aChannel);
// Note: this code is duplicated in PrototypeDocumentContentSink::Init and
// nsScriptSecurityManager::GetChannelResultPrincipals.
// Note: this should match the uri used for the OnNewURI call in
@ -2948,6 +2950,20 @@ void Document::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
mChromeXHRDocBaseURI = nullptr;
if (aLoadGroup) {
nsCOMPtr<nsIInterfaceRequestor> callbacks;
aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
if (callbacks) {
nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
if (loadContext) {
// This is asserting that if we previously set mIsInPrivateBrowsing
// to true from the channel in Document::Reset, that the loadContext
// also believes it to be true.
// MOZ_ASSERT(!mIsInPrivateBrowsing ||
// mIsInPrivateBrowsing == loadContext->UsePrivateBrowsing());
mIsInPrivateBrowsing = loadContext->UsePrivateBrowsing();
}
}
mDocumentLoadGroup = do_GetWeakReference(aLoadGroup);
// there was an assertion here that aLoadGroup was not null. This
// is no longer valid: nsDocShell::SetDocument does not create a
@ -16317,7 +16333,7 @@ bool Document::RecomputeResistFingerprinting() {
bool Document::ShouldResistFingerprinting(RFPTarget aTarget) const {
return mShouldResistFingerprinting &&
nsRFPService::IsRFPEnabledFor(aTarget,
nsRFPService::IsRFPEnabledFor(this->IsInPrivateBrowsing(), aTarget,
mOverriddenFingerprintingSettings);
}
@ -16354,6 +16370,8 @@ void Document::RecordFontFingerprinting() {
nsRFPService::MaybeReportFontFingerprinter(GetChannel(), originNoSuffix);
}
bool Document::IsInPrivateBrowsing() const { return mIsInPrivateBrowsing; }
WindowContext* Document::GetWindowContextForPageUseCounters() const {
if (mDisplayDocument) {
// If we are a resource document, then go through it to find the

View file

@ -4089,6 +4089,7 @@ class Document : public nsINode,
class HighlightRegistry& HighlightRegistry();
bool ShouldResistFingerprinting(RFPTarget aTarget) const;
bool IsInPrivateBrowsing() const;
const Maybe<RFPTarget>& GetOverriddenFingerprintingSettings() const {
return mOverriddenFingerprintingSettings;
@ -4841,6 +4842,9 @@ class Document : public nsINode,
// Whether we should resist fingerprinting.
bool mShouldResistFingerprinting : 1;
// Whether we are in private browsing mode.
bool mIsInPrivateBrowsing : 1;
// Whether we're cloning the contents of an SVG use element.
bool mCloningForSVGUse : 1;

View file

@ -2223,8 +2223,9 @@ bool nsContentUtils::IsCallerChromeOrElementTransformGettersEnabled(
// Older Should RFP Functions ----------------------------------
/* static */
bool nsContentUtils::ShouldResistFingerprinting(RFPTarget aTarget) {
return nsRFPService::IsRFPEnabledFor(aTarget, Nothing());
bool nsContentUtils::ShouldResistFingerprinting(bool aIsPrivateMode,
RFPTarget aTarget) {
return nsRFPService::IsRFPEnabledFor(aIsPrivateMode, aTarget, Nothing());
}
/* static */
@ -2277,6 +2278,7 @@ bool ETPSaysShouldNotResistFingerprinting(nsIChannel* aChannel,
// A positive return from this function should always be obeyed.
// A negative return means we should keep checking things.
bool isPBM = NS_UsePrivateBrowsing(aChannel);
// We do not want this check to apply to RFP, only to FPP
// There is one problematic combination of prefs; however:
// If RFP is enabled in PBMode only and FPP is enabled globally
@ -2286,13 +2288,14 @@ bool ETPSaysShouldNotResistFingerprinting(nsIChannel* aChannel,
if (StaticPrefs::privacy_fingerprintingProtection_DoNotUseDirectly() &&
!StaticPrefs::privacy_resistFingerprinting_DoNotUseDirectly() &&
StaticPrefs::privacy_resistFingerprinting_pbmode_DoNotUseDirectly()) {
if (NS_UsePrivateBrowsing(aChannel)) {
if (isPBM) {
// In PBM (where RFP is enabled) do not exempt based on the ETP toggle
return false;
}
} else if (StaticPrefs::privacy_resistFingerprinting_DoNotUseDirectly() ||
StaticPrefs::
privacy_resistFingerprinting_pbmode_DoNotUseDirectly()) {
(isPBM &&
StaticPrefs::
privacy_resistFingerprinting_pbmode_DoNotUseDirectly())) {
// In RFP, never use the ETP toggle to exempt.
// We can safely return false here even if we are not in PBM mode
// and RFP_pbmode is enabled because we will later see that and
@ -2390,9 +2393,21 @@ inline bool PartionKeyIsAlsoExempted(
bool nsContentUtils::ShouldResistFingerprinting(const char* aJustification,
RFPTarget aTarget) {
// See comment in header file for information about usage
return ShouldResistFingerprinting(aTarget);
// We hardcode PBM to true to be the more restrictive option.
return nsContentUtils::ShouldResistFingerprinting(true, aTarget);
}
namespace {
// This function is only called within this file for Positive Return Checks
bool ShouldResistFingerprinting_(const char* aJustification,
bool aIsPrivateMode, RFPTarget aTarget) {
// See comment in header file for information about usage
return nsContentUtils::ShouldResistFingerprinting(aIsPrivateMode, aTarget);
}
} // namespace
/* static */
bool nsContentUtils::ShouldResistFingerprinting(CallerType aCallerType,
nsIGlobalObject* aGlobalObject,
@ -2416,7 +2431,7 @@ bool nsContentUtils::ShouldResistFingerprinting(nsIDocShell* aDocShell,
MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Info,
("Called nsContentUtils::ShouldResistFingerprinting(nsIDocShell*) "
"with NULL doc"));
return ShouldResistFingerprinting(aTarget);
return ShouldResistFingerprinting("Null Object", aTarget);
}
return doc->ShouldResistFingerprinting(aTarget);
}
@ -2441,7 +2456,12 @@ bool nsContentUtils::ShouldResistFingerprinting(nsIChannel* aChannel,
// With this check, we can ensure that the prefs and target say yes, so only
// an exemption would cause us to return false.
if (!ShouldResistFingerprinting("Positive return check", aTarget)) {
bool isPBM = NS_UsePrivateBrowsing(aChannel);
if (!ShouldResistFingerprinting_("Positive return check", isPBM, aTarget)) {
MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,
("Inside ShouldResistFingerprinting(nsIChannel*)"
" Positive return check said false (PBM: %s)",
isPBM ? "Yes" : "No"));
return false;
}
@ -2524,7 +2544,13 @@ bool nsContentUtils::ShouldResistFingerprinting_dangerous(
const char* aJustification, RFPTarget aTarget) {
// With this check, we can ensure that the prefs and target say yes, so only
// an exemption would cause us to return false.
if (!ShouldResistFingerprinting("Positive return check", aTarget)) {
bool isPBM = aOriginAttributes.mPrivateBrowsingId !=
nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID;
if (!ShouldResistFingerprinting_("Positive return check", isPBM, aTarget)) {
MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,
("Inside ShouldResistFingerprinting_dangerous(nsIURI*,"
" OriginAttributes) Positive return check said false (PBM: %s)",
isPBM ? "Yes" : "No"));
return false;
}
@ -2538,7 +2564,11 @@ bool nsContentUtils::ShouldResistFingerprinting_dangerous(
// If neither of the 'regular' RFP prefs are set, then one (or both)
// of the PBM-Only prefs are set (or we would have failed the
// Positive return check.) Therefore, if we are not in PBM, return false
if (aOriginAttributes.mPrivateBrowsingId == 0) {
if (aOriginAttributes.mPrivateBrowsingId ==
nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID) {
MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,
("Inside ShouldResistFingerprinting_dangerous(nsIURI*,"
" OriginAttributes) OA PBM Check said false"));
return false;
}
}
@ -2581,28 +2611,27 @@ bool nsContentUtils::ShouldResistFingerprinting_dangerous(
return ShouldResistFingerprinting("Null object", aTarget);
}
auto originAttributes =
BasePrincipal::Cast(aPrincipal)->OriginAttributesRef();
// With this check, we can ensure that the prefs and target say yes, so only
// an exemption would cause us to return false.
if (!ShouldResistFingerprinting("Positive return check", aTarget)) {
bool isPBM = originAttributes.mPrivateBrowsingId ==
nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID;
if (!ShouldResistFingerprinting_("Positive return check", isPBM, aTarget)) {
MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,
("Inside ShouldResistFingerprinting(nsIPrincipal*) Positive return "
"check said false (PBM: %s)",
isPBM ? "Yes" : "No"));
return false;
}
if (aPrincipal->IsSystemPrincipal()) {
MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,
("Inside ShouldResistFingerprinting(nsIPrincipal*) System "
"Principal said false"));
return false;
}
auto originAttributes =
BasePrincipal::Cast(aPrincipal)->OriginAttributesRef();
if (!StaticPrefs::privacy_resistFingerprinting_DoNotUseDirectly() &&
!StaticPrefs::privacy_fingerprintingProtection_DoNotUseDirectly()) {
// If neither of the 'regular' RFP prefs are set, then one (or both)
// of the PBM-Only prefs are set (or we would have failed the
// Positive return check.) Therefore, if we are not in PBM, return false
if (originAttributes.mPrivateBrowsingId == 0) {
return false;
}
}
// Exclude internal schemes and web extensions
if (SchemeSaysShouldNotResistFingerprinting(aPrincipal)) {
MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,
@ -2614,7 +2643,7 @@ bool nsContentUtils::ShouldResistFingerprinting_dangerous(
// Web extension principals are also excluded
if (BasePrincipal::Cast(aPrincipal)->AddonPolicy()) {
MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,
("Inside ShouldResistFingerprinting_dangerous(nsIPrincipal*)"
("Inside ShouldResistFingerprinting(nsIPrincipal*)"
" and AddonPolicy said false"));
return false;
}
@ -3878,12 +3907,14 @@ bool nsContentUtils::CanLoadImage(nsIURI* aURI, nsINode* aNode,
}
// static
bool nsContentUtils::IsInPrivateBrowsing(Document* aDoc) {
bool nsContentUtils::IsInPrivateBrowsing(const Document* aDoc) {
if (!aDoc) {
return false;
}
nsCOMPtr<nsILoadGroup> loadGroup = aDoc->GetDocumentLoadGroup();
// See duplicated code below in IsInPrivateBrowsing(nsILoadGroup*)
// and Document::Reset/ResetToURI
if (loadGroup) {
nsCOMPtr<nsIInterfaceRequestor> callbacks;
loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));

View file

@ -350,7 +350,8 @@ class nsContentUtils {
// Check whether we should avoid leaking distinguishing information to JS/CSS.
// This function can be called both in the main thread and worker threads.
static bool ShouldResistFingerprinting(RFPTarget aTarget);
static bool ShouldResistFingerprinting(bool aIsPrivateMode,
RFPTarget aTarget);
static bool ShouldResistFingerprinting(nsIGlobalObject* aGlobalObject,
RFPTarget aTarget);
// Similar to the function above, but always allows CallerType::System
@ -1088,7 +1089,7 @@ class nsContentUtils {
/**
* Returns true if this document is in a Private Browsing window.
*/
static bool IsInPrivateBrowsing(Document* aDoc);
static bool IsInPrivateBrowsing(const Document* aDoc);
/**
* Returns true if this loadGroup uses Private Browsing.

View file

@ -5847,6 +5847,8 @@ PerformanceStorage* WorkerPrivate::GetPerformanceStorage() {
bool WorkerPrivate::ShouldResistFingerprinting(RFPTarget aTarget) const {
return mLoadInfo.mShouldResistFingerprinting &&
nsRFPService::IsRFPEnabledFor(
mLoadInfo.mOriginAttributes.mPrivateBrowsingId >
nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID,
aTarget, mLoadInfo.mOverriddenFingerprintingSettings);
}

View file

@ -46,6 +46,7 @@ WorkletImpl::WorkletImpl(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal)
mWorkletLoadInfo(aWindow),
mTerminated(false),
mFinishedOnExecutionThread(false),
mIsPrivateBrowsing(false),
mTrials(OriginTrials::FromWindow(nsGlobalWindowInner::Cast(aWindow))) {
Unused << NS_WARN_IF(
NS_FAILED(ipc::PrincipalToPrincipalInfo(mPrincipal, &mPrincipalInfo)));
@ -62,6 +63,7 @@ WorkletImpl::WorkletImpl(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal)
RefPtr<dom::Document> doc = nsGlobalWindowInner::Cast(aWindow)->GetDocument();
if (doc) {
mIsPrivateBrowsing = doc->IsInPrivateBrowsing();
mOverriddenFingerprintingSettings =
doc->GetOverriddenFingerprintingSettings();
}

View file

@ -85,7 +85,7 @@ class WorkletImpl {
bool IsSystemPrincipal() const { return mPrincipal->IsSystemPrincipal(); }
bool ShouldResistFingerprinting(RFPTarget aTarget) const {
return mShouldResistFingerprinting &&
nsRFPService::IsRFPEnabledFor(aTarget,
nsRFPService::IsRFPEnabledFor(mIsPrivateBrowsing, aTarget,
mOverriddenFingerprintingSettings);
}
@ -113,16 +113,17 @@ class WorkletImpl {
// Parent thread only.
RefPtr<dom::WorkletThread> mWorkletThread;
bool mTerminated;
bool mTerminated : 1;
// Execution thread only.
RefPtr<dom::WorkletGlobalScope> mGlobalScope;
bool mFinishedOnExecutionThread;
bool mFinishedOnExecutionThread : 1;
Maybe<nsID> mAgentClusterId;
bool mSharedMemoryAllowed;
bool mShouldResistFingerprinting;
bool mSharedMemoryAllowed : 1;
bool mShouldResistFingerprinting : 1;
bool mIsPrivateBrowsing : 1;
// The granular fingerprinting protection overrides applied to the worklet.
// This will only get populated if these is one that comes from the local
// granular override pref or WebCompat. Otherwise, a value of Nothing()

View file

@ -643,7 +643,8 @@ static nsresult FormatTime(
// instead of local time zone name (e.g. CEST).
// To avoid this case when ResistFingerprinting is disabled, use
// |FormatPRTime| to show exact time zone name.
if (!nsContentUtils::ShouldResistFingerprinting(RFPTarget::JSDateTimeUTC)) {
if (!nsContentUtils::ShouldResistFingerprinting(true,
RFPTarget::JSDateTimeUTC)) {
return mozilla::intl::AppDateTimeFormat::Format(aStyleBag, aPrTime,
aStringOut);
}

View file

@ -197,12 +197,13 @@ bool nsRFPService::IsRFPPrefEnabled(bool aIsPrivateMode) {
/* static */
bool nsRFPService::IsRFPEnabledFor(
RFPTarget aTarget,
bool aIsPrivateMode, RFPTarget aTarget,
const Maybe<RFPTarget>& aOverriddenFingerprintingSettings) {
MOZ_ASSERT(aTarget != RFPTarget::AllTargets);
if (StaticPrefs::privacy_resistFingerprinting_DoNotUseDirectly() ||
StaticPrefs::privacy_resistFingerprinting_pbmode_DoNotUseDirectly()) {
(aIsPrivateMode &&
StaticPrefs::privacy_resistFingerprinting_pbmode_DoNotUseDirectly())) {
if (aTarget == RFPTarget::JSLocale) {
return StaticPrefs::privacy_spoof_english() == 2;
}
@ -210,7 +211,9 @@ bool nsRFPService::IsRFPEnabledFor(
}
if (StaticPrefs::privacy_fingerprintingProtection_DoNotUseDirectly() ||
StaticPrefs::privacy_fingerprintingProtection_pbmode_DoNotUseDirectly()) {
(aIsPrivateMode &&
StaticPrefs::
privacy_fingerprintingProtection_pbmode_DoNotUseDirectly())) {
if (aTarget == RFPTarget::IsAlwaysEnabledForPrecompute) {
return true;
}

View file

@ -214,8 +214,9 @@ class nsRFPService final : public nsIObserver, public nsIRFPService {
// 98% of the time you should use nsContentUtils::ShouldResistFingerprinting
// as the difference will not matter to you.
static bool IsRFPPrefEnabled(bool aIsPrivateMode);
static bool IsRFPEnabledFor(
RFPTarget aTarget,
bool aIsPrivateMode, RFPTarget aTarget,
const Maybe<RFPTarget>& aOverriddenFingerprintingSettings);
// --------------------------------------------------------------------------