Bug 1367531: CSP should only check host (not including path) when performing frame ancestors checks. r=dveditz
authorChristoph Kerschbaumer <ckerschb@christophkerschbaumer.com>
Tue, 06 Jun 2017 09:12:13 +0200
changeset 410660 c4cbc063a8e72f5799157a5dd52138d3d465dbac
parent 410659 4ab3d69a2cf09a0c888c8d3d6bc589118cb223d7
child 410661 ebc4d874b576956224e0b66ccb91658a9bf8b347
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdveditz
bugs1367531
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1367531: CSP should only check host (not including path) when performing frame ancestors checks. r=dveditz
dom/security/nsCSPParser.cpp
dom/security/nsCSPParser.h
dom/security/nsCSPUtils.cpp
dom/security/nsCSPUtils.h
--- a/dom/security/nsCSPParser.cpp
+++ b/dom/security/nsCSPParser.cpp
@@ -130,16 +130,17 @@ nsCSPParser::nsCSPParser(cspTokens& aTok
                          bool aDeliveredViaMetaTag)
  : mCurChar(nullptr)
  , mEndChar(nullptr)
  , mHasHashOrNonce(false)
  , mStrictDynamic(false)
  , mUnsafeInlineKeywordSrc(nullptr)
  , mChildSrc(nullptr)
  , mFrameSrc(nullptr)
+ , mParsingFrameAncestorsDir(false)
  , mTokens(aTokens)
  , mSelfURI(aSelfURI)
  , mPolicy(nullptr)
  , mCSPContext(aCSPContext)
  , mDeliveredViaMetaTag(aDeliveredViaMetaTag)
 {
   static bool initialized = false;
   if (!initialized) {
@@ -808,16 +809,17 @@ nsCSPParser::sourceExpression()
     parsedScheme.AssignASCII(selfScheme.get());
   }
 
   // At this point we are expecting a host to be parsed.
   // Trying to create a new nsCSPHost.
   if (nsCSPHostSrc *cspHost = hostSource()) {
     // Do not forget to set the parsed scheme.
     cspHost->setScheme(parsedScheme);
+    cspHost->setWithinFrameAncestorsDir(mParsingFrameAncestorsDir);
     return cspHost;
   }
   // Error was reported in hostSource()
   return nullptr;
 }
 
 // source-list = *WSP [ source-expression *( 1*WSP source-expression ) *WSP ]
 //               / *WSP "'none'" *WSP
@@ -1215,16 +1217,19 @@ nsCSPParser::directive()
   }
 
   // make sure to reset cache variables when trying to invalidate unsafe-inline;
   // unsafe-inline might not only appear in script-src, but also in default-src
   mHasHashOrNonce = false;
   mStrictDynamic = false;
   mUnsafeInlineKeywordSrc = nullptr;
 
+  mParsingFrameAncestorsDir =
+    CSP_IsDirective(mCurDir[0], nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE);
+
   // Try to parse all the srcs by handing the array off to directiveValue
   nsTArray<nsCSPBaseSrc*> srcs;
   directiveValue(srcs);
 
   // If we can not parse any srcs; we let the source expression be the empty set ('none')
   // see, http://www.w3.org/TR/CSP11/#source-list-parsing
   if (srcs.Length() == 0) {
     nsCSPKeywordSrc *keyword = new nsCSPKeywordSrc(CSP_NONE);
--- a/dom/security/nsCSPParser.h
+++ b/dom/security/nsCSPParser.h
@@ -246,16 +246,20 @@ class nsCSPParser {
     // frame-src is deprecated in favor of child-src, however if we
     // see a frame-src directive, it takes precedence for frames and iframes.
     // At the end of parsing, if we have a child-src directive, we need to
     // decide whether it will handle frames, or if there is a frame-src we
     // should honor instead.
     nsCSPChildSrcDirective* mChildSrc;
     nsCSPDirective*         mFrameSrc;
 
+    // cache variable to let nsCSPHostSrc know that it's within
+    // the frame-ancestors directive.
+    bool                    mParsingFrameAncestorsDir;
+
     cspTokens          mTokens;
     nsIURI*            mSelfURI;
     nsCSPPolicy*       mPolicy;
     nsCSPContext*      mCSPContext; // used for console logging
     bool               mDeliveredViaMetaTag;
 };
 
 #endif /* nsCSPParser_h___ */
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -517,16 +517,17 @@ nsCSPSchemeSrc::toString(nsAString& outS
   outStr.AppendASCII(":");
 }
 
 /* ===== nsCSPHostSrc ======================== */
 
 nsCSPHostSrc::nsCSPHostSrc(const nsAString& aHost)
   : mHost(aHost)
   , mGeneratedFromSelfKeyword(false)
+  , mWithinFrameAncstorsDir(false)
 {
   ToLowerCase(mHost);
 }
 
 nsCSPHostSrc::~nsCSPHostSrc()
 {
 }
 
@@ -700,16 +701,21 @@ nsCSPHostSrc::permits(nsIURI* aUri, cons
     if (!url) {
       NS_ASSERTION(false, "can't QI into nsIURI");
       return false;
     }
     nsAutoCString uriPath;
     rv = url->GetFilePath(uriPath);
     NS_ENSURE_SUCCESS(rv, false);
 
+    if (mWithinFrameAncstorsDir) {
+      // no path matching for frame-ancestors to not leak any path information.
+      return true;
+    }
+
     nsString decodedUriPath;
     CSP_PercentDecodeStr(NS_ConvertUTF8toUTF16(uriPath), decodedUriPath);
 
     // check if the last character of mPath is '/'; if so
     // we just have to check loading resource is within
     // the allowed path.
     if (mPath.Last() == '/') {
       if (!StringBeginsWith(decodedUriPath, mPath)) {
--- a/dom/security/nsCSPUtils.h
+++ b/dom/security/nsCSPUtils.h
@@ -252,17 +252,20 @@ class nsCSPHostSrc : public nsCSPBaseSrc
     bool visit(nsCSPSrcVisitor* aVisitor) const;
     void toString(nsAString& outStr) const;
 
     void setScheme(const nsAString& aScheme);
     void setPort(const nsAString& aPort);
     void appendPath(const nsAString &aPath);
 
     inline void setGeneratedFromSelfKeyword() const
-      { mGeneratedFromSelfKeyword = true;}
+      { mGeneratedFromSelfKeyword = true; }
+
+    inline void setWithinFrameAncestorsDir(bool aValue) const
+      { mWithinFrameAncstorsDir = aValue; }
 
     inline void getScheme(nsAString& outStr) const
       { outStr.Assign(mScheme); };
 
     inline void getHost(nsAString& outStr) const
       { outStr.Assign(mHost); };
 
     inline void getPort(nsAString& outStr) const
@@ -272,16 +275,17 @@ class nsCSPHostSrc : public nsCSPBaseSrc
       { outStr.Assign(mPath); };
 
   private:
     nsString mScheme;
     nsString mHost;
     nsString mPort;
     nsString mPath;
     mutable bool mGeneratedFromSelfKeyword;
+    mutable bool mWithinFrameAncstorsDir;
 };
 
 /* =============== nsCSPKeywordSrc ============ */
 
 class nsCSPKeywordSrc : public nsCSPBaseSrc {
   public:
     explicit nsCSPKeywordSrc(CSPKeyword aKeyword);
     virtual ~nsCSPKeywordSrc();