Bug 1543066 - P1 Implement COOP:unsafe-inherit r=nika

Differential Revision: https://phabricator.services.mozilla.com/D40356

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Junior Hsu 2019-08-10 23:24:41 +00:00
parent 772a0b5c03
commit 122ebb1e31
7 changed files with 91 additions and 41 deletions

View File

@ -74,7 +74,8 @@ already_AddRefed<WindowGlobalChild> WindowGlobalChild::Create(
nsCOMPtr<nsIHttpChannelInternal> chan =
do_QueryInterface(aWindow->GetDocument()->GetChannel());
nsILoadInfo::CrossOriginOpenerPolicy policy;
if (chan && NS_SUCCEEDED(chan->GetCrossOriginOpenerPolicy(&policy))) {
if (chan && NS_SUCCEEDED(chan->GetCrossOriginOpenerPolicy(
nsILoadInfo::OPENER_POLICY_NULL, &policy))) {
bc->SetOpenerPolicy(policy);
}

View File

@ -1199,6 +1199,7 @@ interface nsILoadInfo : nsISupports
OPENER_POLICY_NULL = 0,
OPENER_POLICY_SAME_ORIGIN = 1,
OPENER_POLICY_SAME_SITE = 2,
OPENER_POLICY_SAMENESS_MASK = 0x0f,
OPENER_POLICY_EMBEDDER_POLICY_REQUIRE_CORP_FLAG = 0x10,
OPENER_POLICY_UNSAFE_ALLOW_OUTGOING_FLAG = 0x80,
OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP =

View File

@ -636,7 +636,8 @@ void ClassifierDummyChannel::SetHasSandboxedAuxiliaryNavigations(
bool aHasSandboxedAuxiliaryNavigations) {}
NS_IMETHODIMP ClassifierDummyChannel::GetCrossOriginOpenerPolicy(
nsILoadInfo::CrossOriginOpenerPolicy* aPolicy) {
nsILoadInfo::CrossOriginOpenerPolicy aInitiatorPolicy,
nsILoadInfo::CrossOriginOpenerPolicy* aOutPolicy) {
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@ -4299,8 +4299,41 @@ nsresult HttpBaseChannel::GetResponseEmbedderPolicy(
return NS_OK;
}
namespace {
nsILoadInfo::CrossOriginOpenerPolicy GetSameness(
nsILoadInfo::CrossOriginOpenerPolicy aPolicy) {
uint8_t sameness = aPolicy & nsILoadInfo::OPENER_POLICY_SAMENESS_MASK;
return nsILoadInfo::CrossOriginOpenerPolicy(sameness);
}
nsILoadInfo::CrossOriginOpenerPolicy CreateCrossOriginOpenerPolicy(
nsILoadInfo::CrossOriginOpenerPolicy aSameness, bool aUnsafeAllowOutgoing,
bool aEmbedderPolicy) {
uint8_t policy = aSameness;
if (aUnsafeAllowOutgoing) {
policy |= nsILoadInfo::OPENER_POLICY_UNSAFE_ALLOW_OUTGOING_FLAG;
}
if (aEmbedderPolicy) {
policy |= nsILoadInfo::OPENER_POLICY_EMBEDDER_POLICY_REQUIRE_CORP_FLAG;
}
return nsILoadInfo::CrossOriginOpenerPolicy(policy);
}
} // anonymous namespace
// Obtain a cross-origin opener-policy from a response response and a
// cross-origin opener policy initiator.
// https://gist.github.com/annevk/6f2dd8c79c77123f39797f6bdac43f3e
NS_IMETHODIMP HttpBaseChannel::GetCrossOriginOpenerPolicy(
nsILoadInfo::CrossOriginOpenerPolicy* aPolicy) {
nsILoadInfo::CrossOriginOpenerPolicy aInitiatorPolicy,
nsILoadInfo::CrossOriginOpenerPolicy* aOutPolicy) {
MOZ_ASSERT(aOutPolicy);
*aOutPolicy = nsILoadInfo::OPENER_POLICY_NULL;
if (!mResponseHead) {
return NS_ERROR_NOT_AVAILABLE;
}
@ -4309,59 +4342,67 @@ NS_IMETHODIMP HttpBaseChannel::GetCrossOriginOpenerPolicy(
Unused << mResponseHead->GetHeader(nsHttp::Cross_Origin_Opener_Policy,
openerPolicy);
// Cross-Origin-Opener-Policy = sameness [ RWS outgoing ]
// Cross-Origin-Opener-Policy = sameness [ RWS outgoing ] / inherit
// sameness = %s"same-origin" / %s"same-site" ; case-sensitive
// outgoing = %s"unsafe-allow-outgoing" ; case-sensitive
// inherit = %s"unsafe-inherit" ; case-sensitive
Tokenizer t(openerPolicy);
nsAutoCString sameness;
nsAutoCString outgoing;
nsILoadInfo::CrossOriginOpenerPolicy sameness =
nsILoadInfo::OPENER_POLICY_NULL;
bool unsafeAllowOutgoing = false;
bool embedderPolicy = false;
if (openerPolicy.EqualsLiteral("unsafe-inherit")) {
// Step 6
sameness = GetSameness(aInitiatorPolicy);
unsafeAllowOutgoing =
!!(aInitiatorPolicy &
nsILoadInfo::OPENER_POLICY_UNSAFE_ALLOW_OUTGOING_FLAG);
} else {
// Step 7
Tokenizer t(openerPolicy);
nsAutoCString samenessString;
nsAutoCString outgoingString;
// The return value will be true if we find any whitespace. If there is
// whitespace, then it must be followed by "unsafe-allow-outgoing" otherwise
// this is a malformed header value.
bool allowOutgoing = t.ReadUntil(Tokenizer::Token::Whitespace(), sameness);
if (allowOutgoing) {
t.SkipWhites();
bool foundEOF = t.ReadUntil(Tokenizer::Token::EndOfFile(), outgoing);
if (!foundEOF) {
// Malformed response. There should be no text after the second token.
*aPolicy = nsILoadInfo::OPENER_POLICY_NULL;
return NS_OK;
// The return value will be true if we find any whitespace. If there is
// whitespace, then it must be followed by "unsafe-allow-outgoing" otherwise
// this is a malformed header value.
bool unsafeAllowOutgoing =
t.ReadUntil(Tokenizer::Token::Whitespace(), samenessString);
if (unsafeAllowOutgoing) {
t.SkipWhites();
bool foundEOF =
t.ReadUntil(Tokenizer::Token::EndOfFile(), outgoingString);
if (!foundEOF) {
// Malformed response. There should be no text after the second token.
return NS_OK;
}
if (!outgoingString.EqualsLiteral("unsafe-allow-outgoing")) {
// Malformed response. Only one allowed value for the second token.
return NS_OK;
}
}
if (!outgoing.EqualsLiteral("unsafe-allow-outgoing")) {
// Malformed response. Only one allowed value for the second token.
*aPolicy = nsILoadInfo::OPENER_POLICY_NULL;
return NS_OK;
}
}
nsILoadInfo::CrossOriginOpenerPolicy policy = nsILoadInfo::OPENER_POLICY_NULL;
if (sameness.EqualsLiteral("same-origin")) {
policy = nsILoadInfo::OPENER_POLICY_SAME_ORIGIN;
if (allowOutgoing) {
policy = nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_ALLOW_OUTGOING;
}
} else if (sameness.EqualsLiteral("same-site")) {
policy = nsILoadInfo::OPENER_POLICY_SAME_SITE;
if (allowOutgoing) {
policy = nsILoadInfo::OPENER_POLICY_SAME_SITE_ALLOW_OUTGOING;
if (samenessString.EqualsLiteral("same-origin")) {
sameness = nsILoadInfo::OPENER_POLICY_SAME_ORIGIN;
} else if (samenessString.EqualsLiteral("same-site")) {
sameness = nsILoadInfo::OPENER_POLICY_SAME_SITE;
}
}
// Step 9 in obtain a cross-origin opener-policy
// https://gist.github.com/annevk/6f2dd8c79c77123f39797f6bdac43f3e
if (policy == nsILoadInfo::OPENER_POLICY_SAME_ORIGIN) {
if (sameness == nsILoadInfo::OPENER_POLICY_SAME_ORIGIN &&
!unsafeAllowOutgoing) {
nsILoadInfo::CrossOriginEmbedderPolicy coep =
nsILoadInfo::EMBEDDER_POLICY_NULL;
if (NS_SUCCEEDED(GetResponseEmbedderPolicy(&coep)) &&
coep == nsILoadInfo::EMBEDDER_POLICY_REQUIRE_CORP) {
policy =
nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP;
embedderPolicy = true;
}
}
*aPolicy = policy;
*aOutPolicy = CreateCrossOriginOpenerPolicy(sameness, unsafeAllowOutgoing,
embedderPolicy);
return NS_OK;
}

View File

@ -316,7 +316,8 @@ class HttpBaseChannel : public nsHashPropertyBag,
virtual void SetIPv4Disabled(void) override;
virtual void SetIPv6Disabled(void) override;
NS_IMETHOD GetCrossOriginOpenerPolicy(
nsILoadInfo::CrossOriginOpenerPolicy* aPolicy) override;
nsILoadInfo::CrossOriginOpenerPolicy aInitiatorPolicy,
nsILoadInfo::CrossOriginOpenerPolicy* aOutPolicy) override;
virtual bool GetHasSandboxedAuxiliaryNavigations() override {
return mHasSandboxedNavigations;
}
@ -548,6 +549,10 @@ class HttpBaseChannel : public nsHashPropertyBag,
nsresult GetResponseEmbedderPolicy(
nsILoadInfo::CrossOriginEmbedderPolicy* aResponseEmbedderPolicy);
nsresult GetCrossOriginOpenerPolicyWithInitiator(
nsILoadInfo::CrossOriginOpenerPolicy aInitiatorPolicy,
nsILoadInfo::CrossOriginOpenerPolicy* aOutPolicy);
friend class PrivateBrowsingChannel<HttpBaseChannel>;
friend class InterceptFailedOnStop;

View File

@ -7419,7 +7419,7 @@ nsresult nsHttpChannel::ComputeCrossOriginOpenerPolicyMismatch() {
nsILoadInfo::CrossOriginOpenerPolicy documentPolicy = ctx->GetOpenerPolicy();
nsILoadInfo::CrossOriginOpenerPolicy resultPolicy =
nsILoadInfo::OPENER_POLICY_NULL;
GetCrossOriginOpenerPolicy(&resultPolicy);
Unused << GetCrossOriginOpenerPolicy(documentPolicy, &resultPolicy);
if (!ctx->Canonical()->GetCurrentWindowGlobal()) {
return NS_ERROR_NOT_AVAILABLE;

View File

@ -379,7 +379,8 @@ interface nsIHttpChannelInternal : nsISupports
void setIPv6Disabled();
[noscript]
nsILoadInfo_CrossOriginOpenerPolicy getCrossOriginOpenerPolicy();
nsILoadInfo_CrossOriginOpenerPolicy getCrossOriginOpenerPolicy(
in nsILoadInfo_CrossOriginOpenerPolicy aInitiatorPolicy);
[notxpcom, nostdcall] attribute boolean hasSandboxedAuxiliaryNavigations;
};