From bae89898aaa574ce92f4e8f1ea8142e15c9d60b0 Mon Sep 17 00:00:00 2001 From: Kirk Steuber Date: Fri, 10 Mar 2017 10:50:21 -0800 Subject: [PATCH] Bug 1345611 - Change behavior of subdocument Flash blocking to be Third-Party Flash blocking r=bsmedberg,qdot The previous implementation regarding to the Flash Blocking Subdocument list blocked all subdocuments that matched the list. This patch changes that so that subdocuments are only blocked if they are on the Subdocument Block List and also are loaded in a Third-Party context. The changes to cert8.db and key3.db add the https certificate for subdocument.example.com so that testing can verify that a scheme mismatch between the document and its parent results in a third-party classification. MozReview-Commit-ID: IXnA4iPzB4y --HG-- extra : rebase_source : 103c1e184d4219e6db9d00da1ea54674a0e216dd --- build/pgo/certs/cert8.db | Bin 65536 -> 65536 bytes build/pgo/certs/key3.db | Bin 176128 -> 176128 bytes build/pgo/server-locations.txt | 1 + dom/base/nsDocument.cpp | 91 +++++++++++++++++- dom/base/nsDocument.h | 7 +- dom/base/nsIDocument.h | 1 + .../url-classifier/docs/flash-block-lists.rst | 3 +- .../browser/browser_flash_block_lists.js | 18 ++++ 8 files changed, 114 insertions(+), 7 deletions(-) diff --git a/build/pgo/certs/cert8.db b/build/pgo/certs/cert8.db index 1e65b619d39e6c4488202b1fef68a72b82ef9323..611631f1c587420063510da9bfa27949d7f12eff 100644 GIT binary patch delta 604 zcmV-i0;BzafCPYm1h8Cy1xF&~AxE=efaW0;2mt^9Lj*tsKn7$07chbbU@(FO$&)#v zR+G?mEtBxG1sgXoGchnQGBPkTHd+@AGB+?YF)%PPGB7hXT9X}O7?WS4A%ER;>?rMI zoN2PZL;&}nbU?gr`2kIE`_o;h^E&(&i=cOx^fwb6|4syh8`w%Tk)dkNOAms8n9Sqk zG-MTeH2nH%`u@&~?ys7ghu-rGeTaltyl{j$W?E6YQPMFU(d}w@jXQZ`si;VDJ5~lt z644JkH8kYH<~R_t5nWM7dw&`mV6(hf4-a$r0)*qy_RbD+WFW$=gu4No;>oBpQy*k- z7W%+Cw&p=p-oj(~RM4?+SMV2k*LSvE*;4p#%+y(G#7JqVq|Y)b!}yCbS`ChVQp}1WiDfHZGswRaAa?HZftL1WHK&oVPkS{ZDnL> zVJ>5DZL_+je*u4w2H5$ia-W!o*_zYs^Qs# zybt$_$}AT(h28Jq{r2RNjf3I^8i-caqU0z*|2U87lEO%~daE<5dOE-=GiK&2m1Es4 z#th1~i91fxe>gT{lU#Q2fMva2)25%n6^ve3v%4XYN%~y@-LN7mHvB#xOC_s$MQ5_v zU}1)jP#frR1lyF0yM2CaTqWki1Gs7|MC5}KN`Czlnr~~a@=8o5+nRjxt7~a!uN0u> zkL6OT8$D1fDO>p&?c8rrBi;Fi$i+~Na^uo;XL|dcAWq8y0|5X5qk;pRFoFY^FoFY= z1_MRYNSO-QpElWboXwNZJo$+Ox!pMEgo2x8;b~mc$Zq1Nc$|Y*>>oB z%fTvy%yYTzo^PW~^13F8f~eYMMVyWvh+Ao+Po2@>EF-U<&h|CXbu9=@8+e|Gr%WBs3B)$iXVGb6}*A1d`W4o|$3zJIG%`B4b0jE&{bMdG4@{ zIRo+XDlBHXbxPHPZlhDG&;x&Qe8;(JPt8DFKJC0IyYzk>!M0Fzl2+US+3(epDi(bM zxUbJzleRd*U1$0Ac9Z>n7#R5++8gMYxtA;lt5>tf$%reyRIEM4=FfHNTll$6k)GvR z;|97)F08Yzq45a3Qc<=Kd~hK%Z_({3iE!H zEorSenMm<>1-+bb+z@|4<=5_b2Oyk%AeWZ#F zdwaQc0_&vp+kWn-pev^BA^B-f4mnIM64!*R*_(}o&Ca%^KcUj-@t!%xY9J7;%&b?4#VBp zhoy(De+H3#MShEkz%Q&%i7bH3C6We5@x2shC{GSS9dw4$=c&+GFwkNus&V|&abv3f z^@O~BHsZ)-JOQ;KT0oaDyR2dR9^1z|bv3}F^MZ;(^o?$1D;@wINI;x{-EQM#j|(rC z>0F8m*x>5i?8<)voHkWjFNEyk?vpE)5p0OG{k2mDUSJ})PK*TvCL>Y@v29bT`vfh% zl#B8)vtXRM{Lx4204>5Dc{(f!4BC*MR3)%Z>`H?+=m=Ob7Ae9%Gre!6QyUj80#Iyf zqsJnbW$r2>{y#8nD%+#L0>l- z=a;JvVnTm)nV}W9<_>lMOOx52hR0u@P}El!D91bFY6cq3Fg=c{pX3$ z*P^SmnG{!a$t(y2p%|N#H={FQ(_9L}gehV**>9U|t2J$&S*-_i8-(Lz-xgzVfmA0g z71w`|Bo(d&?#dhtwFD1E53tOL$JRSsiWdK1?kH>30%VoB>~}Xdr}Vy7j$eZTL9_U! z?3+r#9NU*N?#(f?j;lr!;@C1MxlGN=Oe2;9+AIm~{|rto6n!06rmRUaFX&SbTq=ia z4a{a8O6WD+bnGbYWSnWTzeE7{pL9UHZux%!O>q0uU8wUq{1=O$cbD`x6CD3e1cMvc zN;Hw7YR*d!f`FLJ Vg2cLxE0bW58-pF%w;kF6& aTableArray, * toolkit/components/url-classifier/flash-block-lists.rst */ FlashClassification -nsDocument::PrincipalFlashClassification(bool aIsTopLevel) +nsDocument::PrincipalFlashClassification() { nsresult rv; + bool isThirdPartyDoc = IsThirdParty(); // If flash blocking is disabled, it is equivalent to all sites being // whitelisted. @@ -13110,7 +13111,7 @@ nsDocument::PrincipalFlashClassification(bool aIsTopLevel) Preferences::GetCString("urlclassifier.flashExceptTable", &denyExceptionsTables); MaybeAddTableToTableList(denyExceptionsTables, tables); - if (!aIsTopLevel) { + if (isThirdPartyDoc) { Preferences::GetCString("urlclassifier.flashSubDocTable", &subDocDenyTables); MaybeAddTableToTableList(subDocDenyTables, tables); @@ -13155,7 +13156,7 @@ nsDocument::PrincipalFlashClassification(bool aIsTopLevel) return FlashClassification::Allowed; } - if (!aIsTopLevel && ArrayContainsTable(results, subDocDenyTables) && + if (isThirdPartyDoc && ArrayContainsTable(results, subDocDenyTables) && !ArrayContainsTable(results, subDocDenyExceptionsTables)) { return FlashClassification::Denied; } @@ -13178,7 +13179,7 @@ nsDocument::ComputeFlashClassification() bool isTopLevel = !parent; FlashClassification classification; if (isTopLevel) { - classification = PrincipalFlashClassification(isTopLevel); + classification = PrincipalFlashClassification(); } else { nsCOMPtr parentDocument = GetParentDocument(); if (!parentDocument) { @@ -13190,7 +13191,7 @@ nsDocument::ComputeFlashClassification() if (parentClassification == FlashClassification::Denied) { classification = FlashClassification::Denied; } else { - classification = PrincipalFlashClassification(isTopLevel); + classification = PrincipalFlashClassification(); // Allow unknown children to inherit allowed status from parent, but // do not allow denied children to do so. @@ -13224,3 +13225,83 @@ nsDocument::DocumentFlashClassification() return mFlashClassification; } + +/** + * Initializes |mIsThirdParty| if necessary and returns its value. The value + * returned represents whether this document should be considered Third-Party. + * + * A top-level document cannot be a considered Third-Party; only subdocuments + * may. For a subdocument to be considered Third-Party, it must meet ANY ONE + * of the following requirements: + * - The document's parent is Third-Party + * - The document has a different scheme (http/https) than its parent document + * - The document's domain and subdomain do not match those of its parent + * document. + * + * If there is an error in determining whether the document is Third-Party, + * it will be assumed to be Third-Party for security reasons. + */ +bool +nsDocument::IsThirdParty() +{ + if (mIsThirdParty.isSome()) { + return mIsThirdParty.value(); + } + + nsCOMPtr docshell = this->GetDocShell(); + if (!docshell) { + mIsThirdParty.emplace(true); + return mIsThirdParty.value(); + } + + nsCOMPtr parent; + nsresult rv = docshell->GetSameTypeParent(getter_AddRefs(parent)); + MOZ_ASSERT(NS_SUCCEEDED(rv), + "nsIDocShellTreeItem::GetSameTypeParent should never fail"); + bool isTopLevel = !parent; + + if (isTopLevel) { + mIsThirdParty.emplace(false); + return mIsThirdParty.value(); + } + + nsCOMPtr parentDocument = GetParentDocument(); + if (!parentDocument) { + // Failure + mIsThirdParty.emplace(true); + return mIsThirdParty.value(); + } + + if (parentDocument->IsThirdParty()) { + mIsThirdParty.emplace(true); + return mIsThirdParty.value(); + } + + nsCOMPtr principal = GetPrincipal(); + nsCOMPtr sop = do_QueryInterface(parentDocument, + &rv); + if (NS_WARN_IF(NS_FAILED(rv) || !sop)) { + // Failure + mIsThirdParty.emplace(true); + return mIsThirdParty.value(); + } + nsCOMPtr parentPrincipal = sop->GetPrincipal(); + + bool principalsMatch = false; + rv = principal->Equals(parentPrincipal, &principalsMatch); + + if (NS_WARN_IF(NS_FAILED(rv))) { + // Failure + mIsThirdParty.emplace(true); + return mIsThirdParty.value(); + } + + if (!principalsMatch) { + mIsThirdParty.emplace(true); + return mIsThirdParty.value(); + } + + // Fall-through. Document is not a Third-Party Document. + mIsThirdParty.emplace(false); + return mIsThirdParty.value(); +} diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h index 5ddb9888da75..f4ae1a0f1dd4 100644 --- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -70,6 +70,7 @@ #include "mozilla/LinkedList.h" #include "CustomElementRegistry.h" #include "mozilla/dom/Performance.h" +#include "mozilla/Maybe.h" #define XML_DECLARATION_BITS_DECLARATION_EXISTS (1 << 0) #define XML_DECLARATION_BITS_ENCODING_EXISTS (1 << 1) @@ -1308,6 +1309,7 @@ protected: void UpdateScreenOrientation(); virtual mozilla::dom::FlashClassification DocumentFlashClassification() override; + virtual bool IsThirdParty() override; #define NS_DOCUMENT_NOTIFY_OBSERVERS(func_, params_) \ NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mObservers, nsIDocumentObserver, \ @@ -1331,7 +1333,7 @@ protected: // Retrieves the classification of the Flash plugins in the document based on // the classification lists. - mozilla::dom::FlashClassification PrincipalFlashClassification(bool aIsTopLevel); + mozilla::dom::FlashClassification PrincipalFlashClassification(); // Attempts to determine the Flash classification of this page based on the // the classification lists and the classification of parent documents. @@ -1383,6 +1385,9 @@ protected: nsWeakPtr mFullscreenRoot; mozilla::dom::FlashClassification mFlashClassification; + // Do not use this value directly. Call the |IsThirdParty()| method, which + // caches its result here. + mozilla::Maybe mIsThirdParty; private: static bool CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp); diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index dbf71347684b..2f3bdfdadd53 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -2903,6 +2903,7 @@ public: // For more information on Flash classification, see // toolkit/components/url-classifier/flash-block-lists.rst virtual mozilla::dom::FlashClassification DocumentFlashClassification() = 0; + virtual bool IsThirdParty() = 0; protected: bool GetUseCounter(mozilla::UseCounter aUseCounter) diff --git a/toolkit/components/url-classifier/docs/flash-block-lists.rst b/toolkit/components/url-classifier/docs/flash-block-lists.rst index 70a7f1404df1..f24fc0d2c040 100644 --- a/toolkit/components/url-classifier/docs/flash-block-lists.rst +++ b/toolkit/components/url-classifier/docs/flash-block-lists.rst @@ -27,7 +27,8 @@ Documents with an Unknown classification will have Flash set to Click To Activat If the document is at the top level (its address is in the URL bar), then the Deny List is checked first followed by the Allow List to determine its classification. -If the document is not at the top level, it will receive a Deny classification if the classification of the parent document is Deny or if the document is on the Deny List or the Sub-Document Deny List. +If the document is not at the top level, it will receive a Deny classification if the classification of the parent document is Deny or if the document is on the Deny List. +It will also receive a Deny classification if the sub-document is not same-origin and the document is on the Sub-Document Deny List. If the document did not receive a Deny classification, it can receive an Allow classification if it is on the Allow List or if the parent document received an Allow classification. If for any reason, the document has a null principal, it will receive a Deny classification. diff --git a/toolkit/components/url-classifier/tests/browser/browser_flash_block_lists.js b/toolkit/components/url-classifier/tests/browser/browser_flash_block_lists.js index 14b4f0e9896a..bace92f57d53 100644 --- a/toolkit/components/url-classifier/tests/browser/browser_flash_block_lists.js +++ b/toolkit/components/url-classifier/tests/browser/browser_flash_block_lists.js @@ -184,6 +184,24 @@ var testCases = [ pluginListed: false, expectedFlashClassification: "denied" }, + { + name: "Sub-document blocked domain in non-Third-Party context", + domains: ["http://subdocument.example.com", "http://subdocument.example.com"], + expectedPluginFallbackType: Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY, + expectedActivated: false, + expectedHasRunningPlugin: false, + pluginListed: true, + expectedFlashClassification: "unknown" + }, + { + name: "Sub-document blocked domain differing only by scheme", + domains: ["http://subdocument.example.com", "https://subdocument.example.com"], + expectedPluginFallbackType: Ci.nsIObjectLoadingContent.PLUGIN_USER_DISABLED, + expectedActivated: false, + expectedHasRunningPlugin: false, + pluginListed: false, + expectedFlashClassification: "denied" + }, { name: "Sub-document blocked subdocument of an allowed domain", domains: ["http://flashallow.example.com", "http://subdocument.example.com"],