Bug 763879 - implement inline stylesheet blocking for CSP (r=dbaron)
authorIan Melven <imelven@mozilla.com>
Thu, 30 Aug 2012 10:58:24 -0700
changeset 139309 9eb574cd8faf9fda76094811db2efffebbcdbeb3
parent 139308 4599f48ce93649d0d3f80be9f87559277a9a3473
child 139310 6b181afc9fadbd4bb9d04648aa24a34bd9731e82
push id3911
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 20:17:26 +0000
treeherdermozilla-aurora@7e26ca8db92b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs763879
milestone24.0a1
Bug 763879 - implement inline stylesheet blocking for CSP (r=dbaron)
content/base/public/nsIContentSecurityPolicy.idl
content/base/src/CSPUtils.jsm
content/base/src/contentSecurityPolicy.js
content/base/src/nsStyleLinkElement.cpp
content/base/src/nsStyledElement.cpp
content/base/test/Makefile.in
content/base/test/file_CSP.css
content/base/test/file_CSP.sjs
content/base/test/file_CSP_inlinescript_main.html
content/base/test/file_CSP_inlinestyle_main.html
content/base/test/file_CSP_inlinestyle_main.html^headers^
content/base/test/file_CSP_inlinestyle_main_spec_compliant.html
content/base/test/file_CSP_inlinestyle_main_spec_compliant.html^headers^
content/base/test/file_CSP_inlinestyle_main_spec_compliant_allowed.html
content/base/test/file_CSP_inlinestyle_main_spec_compliant_allowed.html^headers^
content/base/test/file_CSP_main.html
content/base/test/test_CSP_inlinestyle.html
content/smil/nsSMILCSSValueType.cpp
content/xul/content/src/nsXULElement.cpp
layout/style/nsStyleUtil.cpp
layout/style/nsStyleUtil.h
testing/mochitest/b2g.json
--- a/content/base/public/nsIContentSecurityPolicy.idl
+++ b/content/base/public/nsIContentSecurityPolicy.idl
@@ -8,17 +8,17 @@ interface nsIURI;
 interface nsIHttpChannel;
 interface nsIDocShell;
 
 /**
  * nsIContentSecurityPolicy
  * Describes an XPCOM component used to model an enforce CSPs.
  */
 
-[scriptable, uuid(91E1F257-914C-4D4F-902C-F67F772839AB)]
+[scriptable, uuid(230b126d-afc3-4588-9794-3e135594d626)]
 interface nsIContentSecurityPolicy : nsISupports
 {
 
   /**
    * Set to true when the CSP has been read in and parsed and is ready to
    * enforce.  This is a barrier for the nsDocument so it doesn't load any
    * sub-content until either it knows that a CSP is ready or will not be used.
    */
@@ -58,16 +58,31 @@ interface nsIContentSecurityPolicy : nsI
    *     well.
    * @return
    *     Whether or not the effects of the eval call should be allowed
    *     (block the call if false).
    */
   boolean getAllowsEval(out boolean shouldReportViolation);
 
   /**
+   * Whether this policy allows in-page styles.
+   * This includes <style> tags with text content and style="" attributes in
+   * HTML elements.
+   * @param shouldReportViolation
+   *     Whether or not the use of eval should be reported.
+   *     This function always returns "true" for report-only policies, but when
+   *     the report-only policy is violated, shouldReportViolation is true as
+   *     well.
+   * @return
+   *     Whether or not the effects of the eval call should be allowed
+   *     (block the call if false).
+   */
+  boolean getAllowsInlineStyle(out boolean shouldReportViolation);
+
+  /**
    * Log policy violation on the Error Console and send a report if a report-uri
    * is present in the policy
    *
    * @param violationType
    *     one of the VIOLATION_TYPE_* constants, e.g. inline-script or eval
    * @param sourceFile
    *     name of the source file containing the violation (if available)
    * @param contentSample
@@ -77,16 +92,17 @@ interface nsIContentSecurityPolicy : nsI
    */
   void logViolationDetails(in unsigned short violationType,
                            in AString sourceFile,
                            in AString scriptSample,
                            in int32_t lineNum);
 
   const unsigned short VIOLATION_TYPE_INLINE_SCRIPT = 1;
   const unsigned short VIOLATION_TYPE_EVAL = 2;
+  const unsigned short VIOLATION_TYPE_INLINE_STYLE = 3;
 
   /**
    * Manually triggers violation report sending given a URI and reason.
    * The URI may be null, in which case "self" is sent.
    * @param blockedURI
    *     the URI that violated the policy
    * @param violatedDirective
    *     the directive that was violated.
--- a/content/base/src/CSPUtils.jsm
+++ b/content/base/src/CSPUtils.jsm
@@ -176,16 +176,19 @@ this.CSPRep = function CSPRep(aSpecCompl
   this._allowInlineScripts = false;
 
   // don't auto-populate _directives, so it is easier to find bugs
   this._directives = {};
 
   // Is this a 1.0 spec compliant CSPRep ?
   // Default to false if not specified.
   this._specCompliant = (aSpecCompliant !== undefined) ? aSpecCompliant : false;
+
+  // Only CSP 1.0 spec compliant policies block inline styles by default.
+  this._allowInlineStyles = !aSpecCompliant;
 }
 
 // Source directives for our original CSP implementation.
 // These can be removed when the original implementation is deprecated.
 CSPRep.SRC_DIRECTIVES_OLD = {
   DEFAULT_SRC:      "default-src",
   SCRIPT_SRC:       "script-src",
   STYLE_SRC:        "style-src",
@@ -712,17 +715,18 @@ CSPRep.prototype = {
       return false;
     }
     for (var i in this._directives) {
       if (!that._directives[i] || !this._directives[i].equals(that._directives[i])) {
         return false;
       }
     }
     return (this.allowsInlineScripts === that.allowsInlineScripts)
-        && (this.allowsEvalInScripts === that.allowsEvalInScripts);
+        && (this.allowsEvalInScripts === that.allowsEvalInScripts)
+        && (this.allowsInlineStyles === that.allowsInlineStyles);
   },
 
   /**
    * Generates canonical string representation of the policy.
    */
   toString:
   function csp_toString() {
     var dirs = [];
@@ -807,16 +811,19 @@ CSPRep.prototype = {
     }
 
     newRep._allowEval =          this.allowsEvalInScripts
                            && aCSPRep.allowsEvalInScripts;
 
     newRep._allowInlineScripts = this.allowsInlineScripts
                            && aCSPRep.allowsInlineScripts;
 
+    newRep._allowInlineStyles = this.allowsInlineStyles
+                           && aCSPRep.allowsInlineStyles;
+
     newRep._innerWindowID = this._innerWindowID ?
                               this._innerWindowID : aCSPRep._innerWindowID;
 
     return newRep;
   },
 
   /**
    * Copies default source list to each unspecified directive.
@@ -868,16 +875,24 @@ CSPRep.prototype = {
    * Returns true if inline scripts are enabled through the "inline"
    * keyword.
    */
   get allowsInlineScripts () {
     return this._allowInlineScripts;
   },
 
   /**
+   * Returns true if inline styles are enabled through the "inline-style"
+   * keyword.
+   */
+  get allowsInlineStyles () {
+    return this._allowInlineStyles;
+  },
+
+  /**
    * Sends a warning message to the error console and web developer console.
    * @param aMsg
    *        The message to send
    * @param aSource (optional)
    *        The URL of the file in which the error occurred
    * @param aScriptLine (optional)
    *        The line in the source file which the error occurred
    * @param aLineNum (optional)
--- a/content/base/src/contentSecurityPolicy.js
+++ b/content/base/src/contentSecurityPolicy.js
@@ -35,16 +35,17 @@ function ContentSecurityPolicy() {
   CSPdebug("CSP CREATED");
   this._isInitialized = false;
   this._reportOnlyMode = false;
 
   this._policy = CSPRep.fromString("default-src *");
 
   // default options "wide open" since this policy will be intersected soon
   this._policy._allowInlineScripts = true;
+  this._policy._allowInlineStyles = true;
   this._policy._allowEval = true;
 
   this._request = "";
   this._requestOrigin = "";
   this._requestPrincipal = "";
   this._referrer = "";
   this._docRequest = null;
   CSPdebug("CSP POLICY INITED TO 'default-src *'");
@@ -139,16 +140,24 @@ ContentSecurityPolicy.prototype = {
   getAllowsEval: function(shouldReportViolation) {
     // report it?
     shouldReportViolation.value = !this._policy.allowsEvalInScripts;
 
     // allow it to execute?
     return this._reportOnlyMode || this._policy.allowsEvalInScripts;
   },
 
+  getAllowsInlineStyle: function(shouldReportViolation) {
+    // report it?
+    shouldReportViolation.value = !this._policy.allowsInlineStyles;
+
+    // allow it to execute?
+    return this._reportOnlyMode || this._policy.allowsInlineStyles;
+  },
+
   /**
    * Log policy violation on the Error Console and send a report if a report-uri
    * is present in the policy
    *
    * @param aViolationType
    *     one of the VIOLATION_TYPE_* constants, e.g. inline-script or eval
    * @param aSourceFile
    *     name of the source file containing the violation (if available)
@@ -158,16 +167,22 @@ ContentSecurityPolicy.prototype = {
    *     source line number of the violation (if available)
    */
   logViolationDetails:
   function(aViolationType, aSourceFile, aScriptSample, aLineNum) {
     // allowsInlineScript and allowsEval both return true when report-only mode
     // is enabled, resulting in a call to this function. Therefore we need to
     // check that the policy was in fact violated before logging any violations
     switch (aViolationType) {
+    case Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_INLINE_STYLE:
+      if (!this._policy.allowsInlineStyles)
+        this._asyncReportViolation('self',null,'inline style base restriction',
+                                   'violated base restriction: Inline Stylesheets will not apply',
+                                   aSourceFile, aScriptSample, aLineNum);
+      break;
     case Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_INLINE_SCRIPT:
       if (!this._policy.allowsInlineScripts)
         this._asyncReportViolation('self',null,'inline script base restriction',
                                    'violated base restriction: Inline Scripts will not execute',
                                    aSourceFile, aScriptSample, aLineNum);
       break;
     case Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_EVAL:
       if (!this._policy.allowsEvalInScripts)
--- a/content/base/src/nsStyleLinkElement.cpp
+++ b/content/base/src/nsStyleLinkElement.cpp
@@ -21,16 +21,17 @@
 #include "nsIDOMNode.h"
 #include "nsIDOMStyleSheet.h"
 #include "nsNetUtil.h"
 #include "nsUnicharUtils.h"
 #include "nsCRT.h"
 #include "nsXPCOMCIDInternal.h"
 #include "nsUnicharInputStream.h"
 #include "nsContentUtils.h"
+#include "nsStyleUtil.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsStyleLinkElement::nsStyleLinkElement()
   : mDontLoadStyle(false)
   , mUpdatesEnabled(true)
   , mLineNumber(1)
@@ -361,16 +362,21 @@ nsStyleLinkElement::DoUpdateStyleSheet(n
   }
 
   bool doneLoading = false;
   nsresult rv = NS_OK;
   if (isInline) {
     nsAutoString text;
     nsContentUtils::GetNodeTextContent(thisContent, false, text);
 
+    if (!nsStyleUtil::CSPAllowsInlineStyle(thisContent->NodePrincipal(),
+                                           doc->GetDocumentURI(),
+                                           mLineNumber, text, &rv))
+      return rv;
+
     // Parse the style sheet.
     rv = doc->CSSLoader()->
       LoadInlineStyle(thisContent, text, mLineNumber, title, media,
                       scopeElement, aObserver, &doneLoading, &isAlternate);
   }
   else {
     // XXXbz clone the URI here to work around content policies modifying URIs.
     nsCOMPtr<nsIURI> clonedURI;
--- a/content/base/src/nsStyledElement.cpp
+++ b/content/base/src/nsStyledElement.cpp
@@ -15,16 +15,17 @@
 #include "nsServiceManagerUtils.h"
 #include "nsIDocument.h"
 #include "mozilla/css/StyleRule.h"
 #include "nsCSSParser.h"
 #include "mozilla/css/Loader.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsXULElement.h"
 #include "nsContentUtils.h"
+#include "nsStyleUtil.h"
 
 namespace css = mozilla::css;
 using namespace mozilla::dom;
 
 //----------------------------------------------------------------------
 // nsIContent methods
 
 nsIAtom*
@@ -230,16 +231,21 @@ nsStyledElementNotElementCSSInlineStyle:
 
 void
 nsStyledElementNotElementCSSInlineStyle::ParseStyleAttribute(const nsAString& aValue,
                                                              nsAttrValue& aResult,
                                                              bool aForceInDataDoc)
 {
   nsIDocument* doc = OwnerDoc();
 
+  if (!nsStyleUtil::CSPAllowsInlineStyle(NodePrincipal(),
+                                         doc->GetDocumentURI(), 0, aValue,
+                                         nullptr))
+    return;
+
   if (aForceInDataDoc ||
       !doc->IsLoadedAsData() ||
       doc->IsStaticDocument()) {
     bool isCSS = true; // assume CSS until proven otherwise
 
     if (!IsInNativeAnonymousSubtree()) {  // native anonymous content
                                           // always assumes CSS
       nsAutoString styleType;
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -334,16 +334,17 @@ MOCHITEST_FILES_B = \
 		test_copypaste.html \
 		test_bug503481.html \
 		file_bug503481.sjs \
 		test_bug503481b.html \
 		file_bug503481b_inner.html \
 		test_viewport_scroll.html \
 		test_CSP.html \
 		file_CSP.sjs \
+		file_CSP.css \
 		file_CSP_main.html \
 		file_CSP_main.html^headers^ \
 		file_CSP_main_spec_compliant.html \
 		file_CSP_main_spec_compliant.html^headers^ \
 		file_CSP_main.js \
 		file_CSP_main_spec_compliant.js \
 		test_CSP_frameancestors.html \
 		file_CSP_frameancestors.sjs \
@@ -363,16 +364,23 @@ MOCHITEST_FILES_B = \
 		file_CSP_evalscript_main.html \
 		file_CSP_evalscript_main.html^headers^ \
 		file_CSP_evalscript_main.js \
 		file_CSP_evalscript_main_allowed.js \
 		file_CSP_evalscript_main_spec_compliant.html \
 	 	file_CSP_evalscript_main_spec_compliant.html^headers^ \
 		file_CSP_evalscript_main_spec_compliant_allowed.html \
 		file_CSP_evalscript_main_spec_compliant_allowed.html^headers^ \
+		test_CSP_inlinestyle.html \
+		file_CSP_inlinestyle_main.html \
+		file_CSP_inlinestyle_main.html^headers^ \
+		file_CSP_inlinestyle_main_spec_compliant.html \
+		file_CSP_inlinestyle_main_spec_compliant.html^headers^ \
+		file_CSP_inlinestyle_main_spec_compliant_allowed.html \
+		file_CSP_inlinestyle_main_spec_compliant_allowed.html^headers^ \
 		file_csp_bug768029.html \
 		file_csp_bug768029.sjs \
 		file_csp_bug773891.html \
 		file_csp_bug773891.sjs \
 		test_bug540854.html \
 		bug540854.sjs \
 		test_bug548463.html \
 		test_bug545644.html \
new file mode 100644
--- /dev/null
+++ b/content/base/test/file_CSP.css
@@ -0,0 +1,20 @@
+/*
+ * Moved this CSS from an inline stylesheet to an external file when we added
+ * inline-style blocking in bug 763879.
+ * This test may hang if the load for this .css file is blocked due to a
+ * malfunction of CSP, but should pass if the style_good test passes.
+ */
+
+/* CSS font embedding tests */
+@font-face {
+  font-family: "arbitrary_good";
+  src: url('file_CSP.sjs?testid=font_good&type=application/octet-stream');
+}
+@font-face {
+  font-family: "arbitrary_bad";
+  src: url('http://example.org/tests/content/base/test/file_CSP.sjs?testid=font_bad&type=application/octet-stream');
+}
+
+.div_arbitrary_good { font-family: "arbitrary_good"; }
+.div_arbitrary_bad { font-family: "arbitrary_bad"; }
+
--- a/content/base/test/file_CSP.sjs
+++ b/content/base/test/file_CSP.sjs
@@ -16,12 +16,11 @@ function handleRequest(request, response
 
   if ("type" in query) {
     response.setHeader("Content-Type", unescape(query['type']), false);
   } else {
     response.setHeader("Content-Type", "text/html", false);
   }
 
   if ("content" in query) {
-    response.setHeader("Content-Type", "text/html", false);
     response.write(unescape(query['content']));
   }
 }
--- a/content/base/test/file_CSP_inlinescript_main.html
+++ b/content/base/test/file_CSP_inlinescript_main.html
@@ -1,8 +1,13 @@
+<!--
+-- The original CSP implementation predates the CSP 1.0 spec and didn't
+-- block inline styles, so when the prefixed X-Content-Security-Policy header is used,
+-- as it is for this file, inline styles should be allowed.
+-->
 <html>
   <head>
     <title>CSP inline script tests</title>
   </head>
   <body onload="window.parent.scriptRan(false, 'eventattr', 'event attribute in body tag fired')">
 
     <script type="text/javascript">
       window.parent.scriptRan(false, "textnode", "text node in a script tag executed.");
new file mode 100644
--- /dev/null
+++ b/content/base/test/file_CSP_inlinestyle_main.html
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<html>
+  <head>
+    <title>CSP inline script tests</title>
+    <!-- content= "div#linkstylediv { color: #0f0; }" -->
+    <link rel="stylesheet" type="text/css"
+          href='file_CSP.sjs?type=text/css&content=div%23linkstylediv%20%7B%20color%3A%20%230f0%3B%20%7D' />
+  </head>
+  <body>
+
+    <style type="text/css">
+      div#inlinestylediv {
+        color: #00ff00;
+      }
+    </style>
+
+    <div id='linkstylediv'>Link tag (external) stylesheet test (should be green)</div>
+    <div id='attrstylediv' style="color: #00ff00;">Attribute stylesheet test (should be green)</div>
+    <div id='inlinestylediv'>Inline stylesheet test (should be green)</div>
+
+	    <!-- tests for SMIL stuff - animations -->
+    <svg xmlns="http://www.w3.org/2000/svg"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         width="100%"
+         height="100px">
+
+      <!-- Animates XML attribute, which is mapped into style. -->
+      <text id="xmlTest" x="0" y="15">
+         This should be green since the animation should be allowed by CSP.
+
+        <animate attributeName="fill" attributeType="XML"
+                  values="lime;green;lime" dur="2s"
+                  repeatCount="indefinite" />
+      </text>
+
+      <!-- Animates override value for CSS property. -->
+      <text id="cssOverrideTest" x="0" y="35">
+         This should be green since the animation should be allowed by CSP.
+
+        <animate attributeName="fill" attributeType="CSS"
+                  values="lime;green;lime" dur="2s"
+                  repeatCount="indefinite" />
+      </text>
+
+      <!-- Animates override value for CSS property targeted via ID. -->
+      <text id="cssOverrideTestById" x="0" y="55">
+         This should be green since the animation should be allowed by CSP.
+      </text>
+      <animate xlink:href="#cssOverrideTestById"
+               attributeName="fill"
+               values="lime;green;lime"
+               dur="2s" repeatCount="indefinite" />
+
+      <!-- Sets value for CSS property targeted via ID. -->
+      <text id="cssSetTestById" x="0" y="75">
+         This should be green since the &lt;set&gt; should be allowed by CSP.
+      </text>
+      <set xlink:href="#cssSetTestById"
+               attributeName="fill"
+               to="lime" />
+    </svg>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/file_CSP_inlinestyle_main.html^headers^
@@ -0,0 +1,2 @@
+X-Content-Security-Policy: default-src 'self'
+Cache-Control: no-cache
new file mode 100644
--- /dev/null
+++ b/content/base/test/file_CSP_inlinestyle_main_spec_compliant.html
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<html>
+  <head>
+    <title>CSP inline script tests</title>
+    <!-- content= "div#linkstylediv { color: #0f0; }" -->
+    <link rel="stylesheet" type="text/css"
+          href='file_CSP.sjs?type=text/css&content=div%23linkstylediv%20%7B%20color%3A%20%230f0%3B%20%7D' />
+    <!-- content= "div#modifycsstextdiv { color: #0f0; }" -->
+    <link rel="stylesheet" type="text/css"
+          href='file_CSP.sjs?type=text/css&content=div%23modifycsstextdiv%20%7B%20color%3A%20%23f00%3B%20%7D' />
+    <script>
+      function cssTest() {
+        var elem = document.getElementById('csstextstylediv');
+        elem.style.cssText = "color: #00FF00;";
+        getComputedStyle(elem, null).color;
+
+        document.styleSheets[1].cssRules[0].style.cssText = "color: #00FF00;";
+        elem = document.getElementById('modifycsstextdiv');
+        getComputedStyle(elem, null).color;
+      }
+    </script>
+  </head>
+  <body onload='cssTest()'>
+
+    <style type="text/css">
+      div#inlinestylediv {
+        color: #FF0000;
+      }
+    </style>
+
+    <div id='linkstylediv'>Link tag (external) stylesheet test (should be green)</div>
+    <div id='inlinestylediv'>Inline stylesheet test (should be black)</div>
+    <div id='attrstylediv' style="color: #FF0000;">Attribute stylesheet test (should be black)</div>
+    <div id='csstextstylediv'>cssText test (should be black)</div>
+    <div id='modifycsstextdiv'> modify rule from style sheet via cssText(should be green) </div>
+
+    <!-- tests for SMIL stuff - animations -->
+    <svg xmlns="http://www.w3.org/2000/svg"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         width="100%"
+         height="100px">
+
+      <!-- Animates XML attribute, which is mapped into style. -->
+      <text id="xmlTest" x="0" y="15">
+         This shouldn't be red since the animation should be blocked by CSP.
+
+        <animate attributeName="fill" attributeType="XML"
+                  values="red;orange;red" dur="2s"
+                  repeatCount="indefinite" />
+      </text>
+
+      <!-- Animates override value for CSS property. -->
+      <text id="cssOverrideTest" x="0" y="35">
+         This shouldn't be red since the animation should be blocked by CSP.
+
+        <animate attributeName="fill" attributeType="CSS"
+                  values="red;orange;red" dur="2s"
+                  repeatCount="indefinite" />
+      </text>
+
+      <!-- Animates override value for CSS property targeted via ID. -->
+      <text id="cssOverrideTestById" x="0" y="55">
+         This shouldn't be red since the animation should be blocked by CSP.
+      </text>
+      <animate xlink:href="#cssOverrideTestById"
+               attributeName="fill"
+               values="red;orange;red"
+               dur="2s" repeatCount="indefinite" />
+
+      <!-- Sets value for CSS property targeted via ID. -->
+      <text id="cssSetTestById" x="0" y="75">
+         This shouldn't be red since the &lt;set&gt; should be blocked by CSP.
+      </text>
+      <set xlink:href="#cssSetTestById"
+               attributeName="fill"
+               to="red" />
+    </svg>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/file_CSP_inlinestyle_main_spec_compliant.html^headers^
@@ -0,0 +1,2 @@
+Content-Security-Policy: default-src 'self' ; script-src 'self' 'unsafe-inline'
+Cache-Control: no-cache
new file mode 100644
--- /dev/null
+++ b/content/base/test/file_CSP_inlinestyle_main_spec_compliant_allowed.html
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<html>
+  <head>
+    <title>CSP inline script tests</title>
+    <!-- content= "div#linkstylediv { color: #0f0; }" -->
+    <link rel="stylesheet" type="text/css"
+          href='file_CSP.sjs?type=text/css&content=div%23linkstylediv%20%7B%20color%3A%20%230f0%3B%20%7D' />
+    <!-- content= "div#modifycsstextdiv { color: #f00; }" -->
+    <link rel="stylesheet" type="text/css"
+          href='file_CSP.sjs?type=text/css&content=div%23modifycsstextdiv%20%7B%20color%3A%20%23f00%3B%20%7D' />
+    <script>
+      function cssTest() {
+        // CSSStyleDeclaration.cssText
+        var elem = document.getElementById('csstextstylediv');
+        elem.style.cssText = "color: #00FF00;";
+
+        // If I call getComputedStyle as below, this test passes as the parent page
+        // correctly detects that the text is colored green - if I remove this, getComputedStyle
+        // thinks the text is black when called by the parent page.
+        getComputedStyle(elem, null).color;
+
+        document.styleSheets[1].cssRules[0].style.cssText = "color: #00FF00;";
+        elem = document.getElementById('modifycsstextdiv');
+        getComputedStyle(elem, null).color;
+      }
+    </script>
+  </head>
+  <body onload='cssTest()'>
+
+    <style type="text/css">
+      div#inlinestylediv {
+        color: #00FF00;
+      }
+    </style>
+
+    <div id='linkstylediv'>Link tag (external) stylesheet test (should be green)</div>
+    <div id='inlinestylediv'>Inline stylesheet test (should be green)</div>
+    <div id='attrstylediv' style="color: #00FF00;">Attribute stylesheet test (should be green)</div>
+    <div id='csstextstylediv'>style.cssText test (should be green)</div>
+    <div id='modifycsstextdiv'> modify rule from style sheet via cssText(should be green) </div>
+
+    <!-- tests for SMIL stuff - animations -->
+    <svg xmlns="http://www.w3.org/2000/svg"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         width="100%"
+         height="100px">
+
+      <!-- Animates XML attribute, which is mapped into style. -->
+      <text id="xmlTest" x="0" y="15">
+         This should be green since the animation should be allowed by CSP.
+
+        <animate attributeName="fill" attributeType="XML"
+                  values="lime;green;lime" dur="2s"
+                  repeatCount="indefinite" />
+      </text>
+
+      <!-- Animates override value for CSS property. -->
+      <text id="cssOverrideTest" x="0" y="35">
+         This should be green since the animation should be allowed by CSP.
+
+        <animate attributeName="fill" attributeType="CSS"
+                  values="lime;green;lime" dur="2s"
+                  repeatCount="indefinite" />
+      </text>
+
+      <!-- Animates override value for CSS property targeted via ID. -->
+      <text id="cssOverrideTestById" x="0" y="55">
+         This should be green since the animation should be allowed by CSP.
+      </text>
+      <animate xlink:href="#cssOverrideTestById"
+               attributeName="fill"
+               values="lime;green;lime"
+               dur="2s" repeatCount="indefinite" />
+
+      <!-- Sets value for CSS property targeted via ID. -->
+      <text id="cssSetTestById" x="0" y="75">
+         This should be green since the &lt;set&gt; should be allowed by CSP.
+      </text>
+      <set xlink:href="#cssSetTestById"
+               attributeName="fill"
+               to="lime" />
+    </svg>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/file_CSP_inlinestyle_main_spec_compliant_allowed.html^headers^
@@ -0,0 +1,2 @@
+Content-Security-Policy: default-src 'self' ; script-src 'self' 'unsafe-inline' ; style-src 'self' 'unsafe-inline'
+Cache-Control: no-cache
--- a/content/base/test/file_CSP_main.html
+++ b/content/base/test/file_CSP_main.html
@@ -1,30 +1,20 @@
 <html>
   <head>
     <link rel='stylesheet' type='text/css'
           href='http://example.org/tests/content/base/test/file_CSP.sjs?testid=style_bad&type=text/css' />
     <link rel='stylesheet' type='text/css'
           href='file_CSP.sjs?testid=style_good&type=text/css' />
 
+    <!-- Used to embed inline styles here for testing fonts, but can't do that -->
+    <!-- due to bug 763879 (block inline styles). Moved these to an external, CSS -->
+    <!-- file (file_CSP.css).  -->
+    <link rel='stylesheet' type='text/css' href='file_CSP.css' />
 
-    <style>
-      /* CSS font embedding tests */
-      @font-face {
-        font-family: "arbitrary_good";
-        src: url('file_CSP.sjs?testid=font_good&type=application/octet-stream');
-      }
-      @font-face {
-        font-family: "arbitrary_bad";
-        src: url('http://example.org/tests/content/base/test/file_CSP.sjs?testid=font_bad&type=application/octet-stream');
-      }
-
-      .div_arbitrary_good { font-family: "arbitrary_good"; }
-      .div_arbitrary_bad { font-family: "arbitrary_bad"; }
-    </style>
   </head>
   <body>
     <!-- these should be stopped by CSP.  :) -->
     <img src="http://example.org/tests/content/base/test/file_CSP.sjs?testid=img_bad&type=img/png"> </img>
     <audio src="http://example.org/tests/content/base/test/file_CSP.sjs?testid=media_bad&type=audio/vorbis"></audio>
     <script src='http://example.org/tests/content/base/test/file_CSP.sjs?testid=script_bad&type=text/javascript'></script>
     <iframe src='http://example.org/tests/content/base/test/file_CSP.sjs?testid=frame_bad&content=FAIL'></iframe>
     <object width="10" height="10">
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_CSP_inlinestyle.html
@@ -0,0 +1,142 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Content Security Policy inline stylesheets stuff</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+
+<iframe style="width:100%;height:300px;" id='cspframe'></iframe>
+<iframe style="width:100%;height:300px;" id='cspframe2'></iframe>
+<iframe style="width:100%;height:300px;" id='cspframe3'></iframe>
+<script class="testbody" type="text/javascript">
+
+var path = "/tests/content/base/test/";
+
+
+//////////////////////////////////////////////////////////////////////
+// set up and go
+SimpleTest.waitForExplicitFinish();
+
+var done = 0;
+
+// Our original CSP implementation does not block inline styles.
+function checkStyles(evt) {
+  var cspframe = document.getElementById('cspframe');
+  var color;
+
+  // black means the style wasn't applied.  green colors are used for styles
+  //expected to be applied.  A color is red if a style is erroneously applied
+  color = window.getComputedStyle(cspframe.contentDocument.getElementById('linkstylediv'),null)['color'];
+  ok('rgb(0, 255, 0)' === color, 'External Stylesheet (original CSP implementation) (' + color + ')');
+  color = window.getComputedStyle(cspframe.contentDocument.getElementById('inlinestylediv'),null)['color'];
+  ok('rgb(0, 255, 0)' === color, 'Inline Style TAG (original CSP implementation) (' + color + ')');
+  color = window.getComputedStyle(cspframe.contentDocument.getElementById('attrstylediv'),null)['color'];
+  ok('rgb(0, 255, 0)' === color, 'Style Attribute (original CSP implementation) (' + color + ')');
+  // SMIL tests
+  color = window.getComputedStyle(cspframe.contentDocument.getElementById('xmlTest',null))['fill'];
+  ok('rgb(0, 255, 0)' === color, 'XML Attribute styling (SMIL) (' + color + ')');
+  color = window.getComputedStyle(cspframe.contentDocument.getElementById('cssOverrideTest',null))['fill'];
+  ok('rgb(0, 255, 0)' === color, 'CSS Override styling (SMIL) (' + color + ')');
+  color = window.getComputedStyle(cspframe.contentDocument.getElementById('cssOverrideTestById',null))['fill'];
+  ok('rgb(0, 255, 0)' === color, 'CSS Override styling via ID lookup (SMIL) (' + color + ')');
+  color = window.getComputedStyle(cspframe.contentDocument.getElementById('cssSetTestById',null))['fill'];
+  ok('rgb(0, 255, 0)' === color, 'CSS Set Element styling via ID lookup (SMIL) (' + color + ')');
+  checkIfDone();
+}
+
+// When a CSP 1.0 compliant policy is specified we should block inline
+// styles applied by <style> element, style attribute, and SMIL <animate> and <set> tags
+// (when it's not explicitly allowed.)
+function checkStylesSpecCompliant(evt) {
+  var cspframe = document.getElementById('cspframe2');
+  var color;
+
+  // black means the style wasn't applied.  green colors are used for styles
+  //expected to be applied.  A color is red if a style is erroneously applied
+  color = window.getComputedStyle(cspframe2.contentDocument.getElementById('linkstylediv'),null)['color'];
+  ok('rgb(0, 255, 0)' === color, 'External Stylesheet (CSP 1.0 spec compliant) (' + color + ')');
+  color = window.getComputedStyle(cspframe2.contentDocument.getElementById('inlinestylediv'),null)['color'];
+  ok('rgb(0, 0, 0)' === color, 'Inline Style TAG (CSP 1.0 spec compliant) (' + color + ')');
+  color = window.getComputedStyle(cspframe2.contentDocument.getElementById('attrstylediv'),null)['color'];
+  ok('rgb(0, 0, 0)' === color, 'Style Attribute (CSP 1.0 spec compliant) (' + color + ')');
+  color = window.getComputedStyle(cspframe2.contentDocument.getElementById('csstextstylediv'),null)['color'];
+  ok('rgb(0, 255, 0)' === color, 'cssText (CSP 1.0 spec compliant) (' + color + ')');
+  // SMIL tests
+  color = window.getComputedStyle(cspframe2.contentDocument.getElementById('xmlTest',null))['fill'];
+  ok('rgb(0, 0, 0)' === color, 'XML Attribute styling (SMIL) (' + color + ')');
+  color = window.getComputedStyle(cspframe2.contentDocument.getElementById('cssOverrideTest',null))['fill'];
+  ok('rgb(0, 0, 0)' === color, 'CSS Override styling (SMIL) (' + color + ')');
+  color = window.getComputedStyle(cspframe2.contentDocument.getElementById('cssOverrideTestById',null))['fill'];
+  ok('rgb(0, 0, 0)' === color, 'CSS Override styling via ID lookup (SMIL) (' + color + ')');
+  color = window.getComputedStyle(cspframe2.contentDocument.getElementById('cssSetTestById',null))['fill'];
+  ok('rgb(0, 0, 0)' === color, 'CSS Set Element styling via ID lookup (SMIL) (' + color + ')');
+
+  color = window.getComputedStyle(cspframe2.contentDocument.getElementById('modifycsstextdiv'),null)['color'];
+  ok('rgb(0, 255, 0)' === color, 'Modify loaded style sheet via cssText (' + color + ')');
+
+  checkIfDone();
+}
+
+// When a CSP 1.0 compliant policy is specified we should allow inline
+// styles when it is explicitly allowed.
+function checkStylesSpecCompliantAllowed(evt) {
+  var cspframe = document.getElementById('cspframe3');
+  var color;
+
+  // black means the style wasn't applied.  green colors are used for styles
+  // expected to be applied.  A color is red if a style is erroneously applied
+  color = window.getComputedStyle(cspframe3.contentDocument.getElementById('linkstylediv'),null)['color'];
+  ok('rgb(0, 255, 0)' === color, 'External Stylesheet (CSP 1.0 spec compliant, allowed) (' + color + ')');
+  color = window.getComputedStyle(cspframe3.contentDocument.getElementById('inlinestylediv'),null)['color'];
+  ok('rgb(0, 255, 0)' === color, 'Inline Style TAG (CSP 1.0 spec compliant, allowed) (' + color + ')');
+  color = window.getComputedStyle(cspframe3.contentDocument.getElementById('attrstylediv'),null)['color'];
+  ok('rgb(0, 255, 0)' === color, 'Style Attribute (CSP 1.0 spec compliant, allowed) (' + color + ')');
+
+  // Note that the below test will fail if "script-src: 'unsafe-inline'" breaks,
+  // since it relies on executing script to set .cssText
+  color = window.getComputedStyle(cspframe3.contentDocument.getElementById('csstextstylediv'),null)['color'];
+  ok('rgb(0, 255, 0)' === color, 'style.cssText (CSP 1.0 spec compliant, allowed) (' + color + ')');
+  // SMIL tests
+  color = window.getComputedStyle(cspframe3.contentDocument.getElementById('xmlTest',null))['fill'];
+  ok('rgb(0, 255, 0)' === color, 'XML Attribute styling (SMIL) (' + color + ')');
+  color = window.getComputedStyle(cspframe3.contentDocument.getElementById('cssOverrideTest',null))['fill'];
+  ok('rgb(0, 255, 0)' === color, 'CSS Override styling (SMIL) (' + color + ')');
+  color = window.getComputedStyle(cspframe3.contentDocument.getElementById('cssOverrideTestById',null))['fill'];
+  ok('rgb(0, 255, 0)' === color, 'CSS Override styling via ID lookup (SMIL) (' + color + ')');
+  color = window.getComputedStyle(cspframe3.contentDocument.getElementById('cssSetTestById',null))['fill'];
+  ok('rgb(0, 255, 0)' === color, 'CSS Set Element styling via ID lookup (SMIL) (' + color + ')');
+
+  color = window.getComputedStyle(cspframe3.contentDocument.getElementById('modifycsstextdiv'),null)['color'];
+  ok('rgb(0, 255, 0)' === color, 'Modify loaded style sheet via cssText (' + color + ')');
+
+  checkIfDone();
+}
+
+function checkIfDone() {
+  done++;
+  if (done == 3)
+    SimpleTest.finish();
+}
+
+SpecialPowers.pushPrefEnv(
+  {'set':[["security.csp.speccompliant", true]]},
+  function() {
+    // save this for last so that our listeners are registered.
+    // ... this loads the testbed of good and bad requests.
+    document.getElementById('cspframe').src = 'file_CSP_inlinestyle_main.html';
+    document.getElementById('cspframe').addEventListener('load', checkStyles, false);
+    document.getElementById('cspframe2').src = 'file_CSP_inlinestyle_main_spec_compliant.html';
+    document.getElementById('cspframe2').addEventListener('load', checkStylesSpecCompliant, false);
+    document.getElementById('cspframe3').src = 'file_CSP_inlinestyle_main_spec_compliant_allowed.html';
+    document.getElementById('cspframe3').addEventListener('load', checkStylesSpecCompliantAllowed, false);
+  }
+);
+</script>
+</pre>
+</body>
+</html>
--- a/content/smil/nsSMILCSSValueType.cpp
+++ b/content/smil/nsSMILCSSValueType.cpp
@@ -10,16 +10,17 @@
 #include "nsStyleAnimation.h"
 #include "nsSMILParserUtils.h"
 #include "nsSMILValue.h"
 #include "nsCSSValue.h"
 #include "nsColor.h"
 #include "nsPresContext.h"
 #include "mozilla/dom/Element.h"
 #include "nsDebug.h"
+#include "nsStyleUtil.h"
 
 using namespace mozilla::dom;
 
 /*static*/ nsSMILCSSValueType nsSMILCSSValueType::sSingleton;
 
 struct ValueWrapper {
   ValueWrapper(nsCSSProperty aPropID, const nsStyleAnimation::Value& aValue) :
     mPropID(aPropID), mCSSValue(aValue) {}
@@ -386,16 +387,23 @@ nsSMILCSSValueType::ValueFromString(nsCS
 {
   NS_ABORT_IF_FALSE(aValue.IsNull(), "Outparam should be null-typed");
   nsPresContext* presContext = GetPresContextForElement(aTargetElement);
   if (!presContext) {
     NS_WARNING("Not parsing animation value; unable to get PresContext");
     return;
   }
 
+  nsIDocument* doc = aTargetElement->GetCurrentDoc();
+  if (doc && !nsStyleUtil::CSPAllowsInlineStyle(doc->NodePrincipal(),
+                                                doc->GetDocumentURI(),
+                                                0, aString, nullptr)) {
+    return;
+  }
+
   nsStyleAnimation::Value parsedValue;
   if (ValueFromStringHelper(aPropID, aTargetElement, presContext,
                             aString, parsedValue, aIsContextSensitive)) {
     sSingleton.Init(aValue);
     aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue);
   }
 }
 
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -2300,16 +2300,19 @@ nsXULPrototypeElement::SetAttrAt(uint32_
     else if (mAttributes[aPos].mName.Equals(nsGkAtoms::style)) {
         mHasStyleAttribute = true;
         // Parse the element's 'style' attribute
         nsRefPtr<css::StyleRule> rule;
 
         nsCSSParser parser;
 
         // XXX Get correct Base URI (need GetBaseURI on *prototype* element)
+        // TODO: If we implement Content Security Policy for chrome documents
+        // as has been discussed, the CSP should be checked here to see if
+        // inline styles are allowed to be applied.
         parser.ParseStyleAttribute(aValue, aDocumentURI, aDocumentURI,
                                    // This is basically duplicating what
                                    // nsINode::NodePrincipal() does
                                    mNodeInfo->NodeInfoManager()->
                                      DocumentPrincipal(),
                                    getter_AddRefs(rule));
         if (rule) {
             mAttributes[aPos].mValue.SetTo(rule, &aValue);
--- a/layout/style/nsStyleUtil.cpp
+++ b/layout/style/nsStyleUtil.cpp
@@ -5,16 +5,17 @@
 
 #include "nsStyleUtil.h"
 #include "nsStyleConsts.h"
 
 #include "nsIContent.h"
 #include "nsReadableUtils.h"
 #include "nsCSSProps.h"
 #include "nsRuleNode.h"
+#include "nsIContentSecurityPolicy.h"
 
 using namespace mozilla;
 
 //------------------------------------------------------------------------------
 // Font Algorithm Code
 //------------------------------------------------------------------------------
 
 // Compare two language strings
@@ -410,8 +411,66 @@ nsStyleUtil::IsSignificantChild(nsIConte
     return true;
   }
 
   return aTextIsSignificant && isText && aChild->TextLength() != 0 &&
          (aWhitespaceIsSignificant ||
           !aChild->TextIsOnlyWhitespace());
 }
 
+/* static */ bool
+nsStyleUtil::CSPAllowsInlineStyle(nsIPrincipal* aPrincipal,
+                                  nsIURI* aSourceURI,
+                                  uint32_t aLineNumber,
+                                  const nsSubstring& aStyleText,
+                                  nsresult* aRv)
+{
+  nsresult rv;
+
+  if (aRv) {
+    *aRv = NS_OK;
+  }
+
+  nsCOMPtr<nsIContentSecurityPolicy> csp;
+  rv = aPrincipal->GetCsp(getter_AddRefs(csp));
+
+  if (NS_FAILED(rv)) {
+    if (aRv)
+      *aRv = rv;
+    return false;
+  }
+
+  if (csp) {
+    bool inlineOK = true;
+    bool reportViolation = false;
+    rv = csp->GetAllowsInlineStyle(&reportViolation, &inlineOK);
+    if (NS_FAILED(rv)) {
+      if (aRv)
+        *aRv = rv;
+      return false;
+    }
+
+    if (reportViolation) {
+      // Inline styles are not allowed by CSP, so report the violation
+      nsAutoCString asciiSpec;
+      aSourceURI->GetAsciiSpec(asciiSpec);
+      nsAutoString styleText(aStyleText);
+
+      // cap the length of the style sample at 40 chars.
+      if (styleText.Length() > 40) {
+        styleText.Truncate(40);
+        styleText.Append(NS_LITERAL_STRING("..."));
+      }
+
+      csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_STYLE,
+                              NS_ConvertUTF8toUTF16(asciiSpec),
+                              aStyleText,
+                              aLineNumber);
+    }
+
+    if (!inlineOK) {
+        // The inline style should be blocked.
+        return false;
+    }
+  }
+  // No CSP or a CSP that allows inline styles.
+  return true;
+}
--- a/layout/style/nsStyleUtil.h
+++ b/layout/style/nsStyleUtil.h
@@ -2,16 +2,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef nsStyleUtil_h___
 #define nsStyleUtil_h___
 
 #include "nsCoord.h"
 #include "nsCSSProperty.h"
+#include "nsIPrincipal.h"
+#include "nsSubstring.h"
 #include "gfxFontFeatures.h"
 
 class nsCSSValue;
 class nsStringComparator;
 class nsIContent;
 struct gfxFontFeature;
 class nsCSSValueList;
 template <class E> class nsTArray;
@@ -85,12 +87,28 @@ public:
   static float ColorComponentToFloat(uint8_t aAlpha);
 
   /*
    * Does this child count as significant for selector matching?
    */
   static bool IsSignificantChild(nsIContent* aChild,
                                    bool aTextIsSignificant,
                                    bool aWhitespaceIsSignificant);
+  /*
+   *  Does this principal have a CSP that blocks the application of
+   *  inline styles ? Returns false if application of the style should
+   *  be blocked.
+   *
+   *  Note that the principal passed in here needs to be the principal
+   *  of the document, not of the style sheet. The document's principal
+   *  is where any Content Security Policy that should be used to
+   *  block or allow inline styles will be located.
+   */
+  static bool CSPAllowsInlineStyle(nsIPrincipal* aPrincipal,
+                                   nsIURI* aSourceURI,
+                                   uint32_t aLineNumber,
+                                   const nsSubstring& aStyleText,
+                                   nsresult* aRv);
+
 };
 
 
 #endif /* nsStyleUtil_h___ */
--- a/testing/mochitest/b2g.json
+++ b/testing/mochitest/b2g.json
@@ -22,16 +22,17 @@
     "dom/imptests/webapps/DOMCore/tests/approved/test_Range-mutations.html":"Test timed out.",
     "dom/encoding/test/test_stringencoding.html":"Test timed out on b2g board",
 
     "content/events/test/test_bug615597.html":"", 
     "content/html/content/test/forms/test_input_sanitization.html":"",
     "dom/tests/mochitest/ajax/jquery/test_jQuery.html":"",
  
     "content/base/test/test_CSP_inlinescript.html":"",
+    "content/base/test/test_CSP_inlinestyle.html":"",
     "content/base/test/test_XHRSendData.html":"",
     "content/base/test/test_XHR_parameters.html":"",
     "content/base/test/test_XHR_system.html":"",
     "content/base/test/test_base.xhtml":"",
     "content/base/test/test_bug338583.html":"",
     "content/base/test/test_bug372086.html":"",
     "content/base/test/test_bug466080.html":"",
     "content/base/test/test_bug475156.html":"",