[tor-commits] [tor-browser/tor-browser-31.5.0esr-4.5-1] Bug 12827: Create preference to disable SVG.

mikeperry at torproject.org mikeperry at torproject.org
Sat Mar 21 02:41:05 UTC 2015


commit 7dd093abb5c68728b5ba6c940cca224345d89f3e
Author: Kathy Brade <brade at pearlcrescent.com>
Date:   Wed Mar 18 15:21:30 2015 -0400

    Bug 12827: Create preference to disable SVG.
    
    If the svg.inContent.enabled preference is false, disallow all use of
    SVG within content pages.
    
    In the following situations it is very difficult to determine if code
    is executing within a chrome context or not:
      SVG hasFeature() API.
      SVG hasExtension() API.
      Use of SVG glyphs within custom OpenType fonts.
    In these cases, everything is assumed to be content; that is, setting
    the pref. to false will block use of the above features from chrome
    as well. This is OK because these features are unlikely to be used by
    core browser code.
---
 browser/app/profile/000-tor-browser.js      |    1 +
 content/base/src/nsNameSpaceManager.cpp     |    3 ++-
 content/base/src/nsObjectLoadingContent.cpp |   16 +++++++++---
 content/svg/content/src/nsSVGFeatures.cpp   |   13 ++++++++++
 gfx/thebes/gfxFont.cpp                      |    6 ++++-
 image/src/ImageFactory.cpp                  |   33 ++++++++++++++++--------
 layout/base/nsCSSFrameConstructor.cpp       |   15 +++++++----
 layout/build/nsContentDLF.cpp               |   27 +++++++++++--------
 layout/svg/nsSVGUtils.cpp                   |   37 +++++++++++++++++++++++++++
 layout/svg/nsSVGUtils.h                     |    3 +++
 uriloader/base/nsURILoader.cpp              |   13 +++++++---
 11 files changed, 131 insertions(+), 36 deletions(-)

diff --git a/browser/app/profile/000-tor-browser.js b/browser/app/profile/000-tor-browser.js
index ceb9394..e87ccff 100644
--- a/browser/app/profile/000-tor-browser.js
+++ b/browser/app/profile/000-tor-browser.js
@@ -116,6 +116,7 @@ pref("plugins.click_to_play", true);
 pref("plugin.state.flash", 1);
 pref("plugins.hide_infobar_for_missing_plugin", true);
 pref("media.peerconnection.enabled", false); // Disable WebRTC interfaces
+pref("svg.inContent.enabled", true); // May be disabled via Torbutton's security slider.
 
 // Network and performance
 pref("network.http.pipelining", true);
diff --git a/content/base/src/nsNameSpaceManager.cpp b/content/base/src/nsNameSpaceManager.cpp
index 409e08c..3f4f9f8 100644
--- a/content/base/src/nsNameSpaceManager.cpp
+++ b/content/base/src/nsNameSpaceManager.cpp
@@ -17,6 +17,7 @@
 #include "nsContentCreatorFunctions.h"
 #include "nsString.h"
 #include "nsINodeInfo.h"
+#include "nsSVGUtils.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/XBLChildrenElement.h"
 #include "mozilla/dom/Element.h"
@@ -153,7 +154,7 @@ NS_NewElement(Element** aResult,
   if (ns == kNameSpaceID_MathML) {
     return NS_NewMathMLElement(aResult, ni.forget());
   }
-  if (ns == kNameSpaceID_SVG) {
+  if (ns == kNameSpaceID_SVG && NS_SVGEnabled(ni->GetDocument())) {
     return NS_NewSVGElement(aResult, ni.forget(), aFromParser);
   }
   if (ns == kNameSpaceID_XBL && ni->Equals(nsGkAtoms::children)) {
diff --git a/content/base/src/nsObjectLoadingContent.cpp b/content/base/src/nsObjectLoadingContent.cpp
index 8d9bdaa..d14c83e 100644
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -57,6 +57,7 @@
 #include "nsMimeTypes.h"
 #include "nsStyleUtil.h"
 #include "nsUnicharUtils.h"
+#include "nsSVGUtils.h"
 #include "mozilla/Preferences.h"
 #include "nsSandboxFlags.h"
 
@@ -2530,9 +2531,18 @@ nsObjectLoadingContent::GetTypeOfContent(const nsCString& aMIMEType)
 
   // SVGs load as documents, but are their own capability
   bool isSVG = aMIMEType.LowerCaseEqualsLiteral("image/svg+xml");
-  Capabilities supportType = isSVG ? eSupportSVG : eSupportDocuments;
-  if ((caps & supportType) && IsSupportedDocument(aMIMEType)) {
-    return eType_Document;
+  bool isSVGEnabled = false;
+  if (isSVG) {
+    nsCOMPtr<nsIContent> thisContent =
+              do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
+    isSVGEnabled = NS_SVGEnabled(thisContent->OwnerDoc());
+  }
+
+  if (isSVGEnabled || !isSVG) {
+    Capabilities supportType = isSVG ? eSupportSVG : eSupportDocuments;
+    if ((caps & supportType) && IsSupportedDocument(aMIMEType)) {
+      return eType_Document;
+    }
   }
 
   if (caps & eSupportPlugins && PluginExistsForType(aMIMEType.get())) {
diff --git a/content/svg/content/src/nsSVGFeatures.cpp b/content/svg/content/src/nsSVGFeatures.cpp
index 153a00c..04e9917 100644
--- a/content/svg/content/src/nsSVGFeatures.cpp
+++ b/content/svg/content/src/nsSVGFeatures.cpp
@@ -13,6 +13,7 @@
  */
 
 #include "nsSVGFeatures.h"
+#include "nsSVGUtils.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "mozilla/Preferences.h"
@@ -22,6 +23,12 @@ using namespace mozilla;
 /*static*/ bool
 nsSVGFeatures::HasFeature(nsISupports* aObject, const nsAString& aFeature)
 {
+  // Since we do not have access to the document here we pass nullptr, which
+  // means only the svg.inContent.enabled pref is checked. This is OK since
+  // we do not expect chrome code to use the HasFeature() API.
+  if (!NS_SVGEnabled(nullptr))
+    return false;
+
   if (aFeature.EqualsLiteral("http://www.w3.org/TR/SVG11/feature#Script")) {
     nsCOMPtr<nsIContent> content(do_QueryInterface(aObject));
     if (content) {
@@ -44,6 +51,12 @@ nsSVGFeatures::HasFeature(nsISupports* aObject, const nsAString& aFeature)
 /*static*/ bool
 nsSVGFeatures::HasExtension(const nsAString& aExtension)
 {
+  // Since we do not have access to the document here we pass nullptr, which
+  // means only the svg.inContent.enabled pref is checked. This is OK since
+  // we do not expect chrome code to use the HasExtension() API.
+  if (!NS_SVGEnabled(nullptr))
+    return false;
+
 #define SVG_SUPPORTED_EXTENSION(str) if (aExtension.EqualsLiteral(str)) return true;
   SVG_SUPPORTED_EXTENSION("http://www.w3.org/1999/xhtml")
   SVG_SUPPORTED_EXTENSION("http://www.w3.org/1998/Math/MathML")
diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp
index c5e2957..da25374 100644
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -38,6 +38,7 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
+#include "nsSVGUtils.h"
 #include "gfxSVGGlyphs.h"
 #include "gfxMathTable.h"
 #include "gfx2DGlue.h"
@@ -364,7 +365,10 @@ gfxFontEntry::RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId,
 bool
 gfxFontEntry::TryGetSVGData(gfxFont* aFont)
 {
-    if (!gfxPlatform::GetPlatform()->OpenTypeSVGEnabled()) {
+    // For the NS_SVGEnabled() check, we pass nullptr because we do not have
+    // access to the document here. That is OK because we do not expect
+    // chrome documents to use custom fonts that contain embedded SVG glyphs.
+    if (!gfxPlatform::GetPlatform()->OpenTypeSVGEnabled() || !NS_SVGEnabled(nullptr)) {
         return false;
     }
 
diff --git a/image/src/ImageFactory.cpp b/image/src/ImageFactory.cpp
index 2daba13..578f95c 100644
--- a/image/src/ImageFactory.cpp
+++ b/image/src/ImageFactory.cpp
@@ -20,6 +20,7 @@
 #include "Image.h"
 #include "nsMediaFragmentURIParser.h"
 #include "nsContentUtils.h"
+#include "nsSVGUtils.h"
 #include "nsIScriptSecurityManager.h"
 
 #include "ImageFactory.h"
@@ -110,6 +111,17 @@ ImageFactory::CanRetargetOnDataAvailable(ImageURL* aURI, bool aIsMultiPart)
   return true;
 }
 
+// Marks an image as having an error before returning it. Used with macros like
+// NS_ENSURE_SUCCESS, since we guarantee to always return an image even if an
+// error occurs, but callers need to be able to tell that this happened.
+template <typename T>
+static already_AddRefed<Image>
+BadImage(nsRefPtr<T>& image)
+{
+  image->SetHasError();
+  return image.forget();
+}
+
 /* static */ already_AddRefed<Image>
 ImageFactory::CreateImage(nsIRequest* aRequest,
                           imgStatusTracker* aStatusTracker,
@@ -126,6 +138,16 @@ ImageFactory::CreateImage(nsIRequest* aRequest,
 
   // Select the type of image to create based on MIME type.
   if (aMimeType.EqualsLiteral(IMAGE_SVG_XML)) {
+    nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
+    if (!NS_SVGEnabledForChannel(channel)) {
+      // SVG is disabled.  We must return an image object that is marked
+      // "bad", but we want to avoid invoking the VectorImage class (SVG code),
+      // so we return a PNG with the error flag set.
+      nsRefPtr<RasterImage> badImage = new RasterImage(aStatusTracker, aURI);
+      (void)badImage->Init(IMAGE_PNG, Image::INIT_FLAG_NONE);
+      return BadImage(badImage);
+    }
+
     return CreateVectorImage(aRequest, aStatusTracker, aMimeType,
                              aURI, imageFlags, aInnerWindowId);
   } else {
@@ -134,17 +156,6 @@ ImageFactory::CreateImage(nsIRequest* aRequest,
   }
 }
 
-// Marks an image as having an error before returning it. Used with macros like
-// NS_ENSURE_SUCCESS, since we guarantee to always return an image even if an
-// error occurs, but callers need to be able to tell that this happened.
-template <typename T>
-static already_AddRefed<Image>
-BadImage(nsRefPtr<T>& image)
-{
-  image->SetHasError();
-  return image.forget();
-}
-
 /* static */ already_AddRefed<Image>
 ImageFactory::CreateAnonymousImage(const nsCString& aMimeType)
 {
diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp
index 5cab7ca..786e3c2 100644
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -89,6 +89,7 @@
 #include "nsMathMLParts.h"
 #include "mozilla/dom/SVGTests.h"
 #include "nsSVGUtils.h"
+#include "nsIDOMSVGElement.h"
 
 #include "nsRefreshDriver.h"
 #include "nsRuleProcessorData.h"
@@ -2423,7 +2424,8 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element*                 aDocEle
   else
 #endif
   if (aDocElement->IsSVG()) {
-    if (aDocElement->Tag() != nsGkAtoms::svg) {
+    nsCOMPtr<nsIDOMSVGElement> svgElem = do_QueryInterface(aDocElement);
+    if (!svgElem || (aDocElement->Tag() != nsGkAtoms::svg)) {
       return nullptr;
     }
     // We're going to call the right function ourselves, so no need to give a
@@ -5296,10 +5298,13 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
       data = FindMathMLData(element, aTag, aNameSpaceID, styleContext);
     }
     if (!data) {
-      data = FindSVGData(element, aTag, aNameSpaceID, aParentFrame,
-                         aFlags & ITEM_IS_WITHIN_SVG_TEXT,
-                         aFlags & ITEM_ALLOWS_TEXT_PATH_CHILD,
-                         styleContext);
+      nsCOMPtr<nsIDOMSVGElement> svgElem = do_QueryInterface(element);
+      if (svgElem) {
+        data = FindSVGData(element, aTag, aNameSpaceID, aParentFrame,
+                          aFlags & ITEM_IS_WITHIN_SVG_TEXT,
+                          aFlags & ITEM_ALLOWS_TEXT_PATH_CHILD,
+                          styleContext);
+      }
     }
 
     // Now check for XUL display types
diff --git a/layout/build/nsContentDLF.cpp b/layout/build/nsContentDLF.cpp
index d3081dd..1275590 100644
--- a/layout/build/nsContentDLF.cpp
+++ b/layout/build/nsContentDLF.cpp
@@ -25,6 +25,7 @@
 #include "nsCRT.h"
 #include "nsIViewSourceChannel.h"
 #include "nsContentUtils.h"
+#include "nsSVGUtils.h"
 #include "imgLoader.h"
 #include "nsCharsetSource.h"
 #include "nsMimeTypes.h"
@@ -171,9 +172,11 @@ nsContentDLF::CreateInstance(const char* aCommand,
       }
     }
 
-    for (typeIndex = 0; gSVGTypes[typeIndex] && !knownType; ++typeIndex) {
-      if (type.Equals(gSVGTypes[typeIndex])) {
-        knownType = true;
+    if (NS_SVGEnabledForChannel(aChannel)) {
+      for (typeIndex = 0; gSVGTypes[typeIndex] && !knownType; ++typeIndex) {
+        if (type.Equals(gSVGTypes[typeIndex])) {
+          knownType = true;
+        }
       }
     }
 
@@ -218,14 +221,16 @@ nsContentDLF::CreateInstance(const char* aCommand,
     }
   }
 
-  // Try SVG
-  typeIndex = 0;
-  while(gSVGTypes[typeIndex]) {
-    if (!PL_strcmp(gSVGTypes[typeIndex++], aContentType)) {
-      return CreateDocument(aCommand,
-                            aChannel, aLoadGroup,
-                            aContainer, kSVGDocumentCID,
-                            aDocListener, aDocViewer);
+  if (NS_SVGEnabledForChannel(aChannel)) {
+    // Try SVG
+    typeIndex = 0;
+    while(gSVGTypes[typeIndex]) {
+      if (!PL_strcmp(gSVGTypes[typeIndex++], aContentType)) {
+        return CreateDocument(aCommand,
+                              aChannel, aLoadGroup,
+                              aContainer, kSVGDocumentCID,
+                              aDocListener, aDocViewer);
+      }
     }
   }
 
diff --git a/layout/svg/nsSVGUtils.cpp b/layout/svg/nsSVGUtils.cpp
index 3ebfbd7..da55070 100644
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -48,6 +48,8 @@
 #include "nsSVGPaintServerFrame.h"
 #include "mozilla/dom/SVGSVGElement.h"
 #include "nsTextFrame.h"
+#include "nsNetUtil.h"
+#include "nsContentUtils.h"
 #include "SVGContentUtils.h"
 #include "mozilla/unused.h"
 
@@ -55,9 +57,41 @@ using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 
+static bool sSVGEnabledInContent;
 static bool sSVGDisplayListHitTestingEnabled;
 static bool sSVGDisplayListPaintingEnabled;
 
+// Determine if SVG should be enabled for aDoc.  The svg.inContent.enabled
+// preference is checked as well as whether aDoc is a content or chrome doc.
+// If aChannel is NULL, the pref. value is returned.
+bool
+NS_SVGEnabled(nsIDocument *aDoc)
+{
+  return NS_SVGEnabledForChannel(aDoc ? aDoc->GetChannel() : nullptr);
+}
+
+// Determine if SVG should be enabled for aChannel.  The svg.inContent.enabled
+// preference is checked as well as whether the load context associated with
+// aChannel is content or chrome.
+// If aChannel is NULL, the pref. value is returned.
+bool
+NS_SVGEnabledForChannel(nsIChannel *aChannel)
+{
+  if (sSVGEnabledInContent)
+    return true;
+
+  if (!aChannel)
+    return false;
+
+  bool isContent = true;
+  nsCOMPtr<nsILoadContext> ctx;
+  NS_QueryNotificationCallbacks(aChannel, ctx);
+  if (ctx)
+    ctx->GetIsContent(&isContent);
+
+  return !isContent;
+}
+
 bool
 NS_SVGDisplayListHitTestingEnabled()
 {
@@ -125,6 +159,9 @@ SVGAutoRenderState::IsPaintingToWindow(nsRenderingContext *aContext)
 void
 nsSVGUtils::Init()
 {
+  Preferences::AddBoolVarCache(&sSVGEnabledInContent,
+                               "svg.inContent.enabled");
+
   Preferences::AddBoolVarCache(&sSVGDisplayListHitTestingEnabled,
                                "svg.display-lists.hit-testing.enabled");
 
diff --git a/layout/svg/nsSVGUtils.h b/layout/svg/nsSVGUtils.h
index 5f99fa7..0cd67b8 100644
--- a/layout/svg/nsSVGUtils.h
+++ b/layout/svg/nsSVGUtils.h
@@ -77,6 +77,9 @@ class SourceSurface;
 bool NS_SVGDisplayListHitTestingEnabled();
 bool NS_SVGDisplayListPaintingEnabled();
 
+bool NS_SVGEnabled(nsIDocument *aDoc);
+bool NS_SVGEnabledForChannel(nsIChannel *aChannel);
+
 /**
  * Sometimes we need to distinguish between an empty box and a box
  * that contains an element that has no size e.g. a point at the origin.
diff --git a/uriloader/base/nsURILoader.cpp b/uriloader/base/nsURILoader.cpp
index e1545f2..1871784 100644
--- a/uriloader/base/nsURILoader.cpp
+++ b/uriloader/base/nsURILoader.cpp
@@ -37,6 +37,7 @@
 #include "nsNetUtil.h"
 #include "nsThreadUtils.h"
 #include "nsReadableUtils.h"
+#include "nsSVGUtils.h"
 #include "nsError.h"
 
 #include "nsICategoryManager.h"
@@ -442,11 +443,15 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest *request, nsISupports *
       //
       // Fourth step: try to find an nsIContentHandler for our type.
       //
-      nsAutoCString handlerContractID (NS_CONTENT_HANDLER_CONTRACTID_PREFIX);
-      handlerContractID += mContentType;
+      nsCOMPtr<nsIContentHandler> contentHandler;
+      if (!mContentType.EqualsASCII(IMAGE_SVG_XML) ||
+          NS_SVGEnabledForChannel(aChannel)) {
+        nsAutoCString handlerContractID (NS_CONTENT_HANDLER_CONTRACTID_PREFIX);
+        handlerContractID += mContentType;
+
+        contentHandler = do_CreateInstance(handlerContractID.get());
+      }
 
-      nsCOMPtr<nsIContentHandler> contentHandler =
-        do_CreateInstance(handlerContractID.get());
       if (contentHandler) {
         LOG(("  Content handler found"));
         rv = contentHandler->HandleContent(mContentType.get(),





More information about the tor-commits mailing list