diff options
Diffstat (limited to 'dom/base/nsTreeSanitizer.h')
-rw-r--r-- | dom/base/nsTreeSanitizer.h | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/dom/base/nsTreeSanitizer.h b/dom/base/nsTreeSanitizer.h new file mode 100644 index 0000000000..ed1c49c60c --- /dev/null +++ b/dom/base/nsTreeSanitizer.h @@ -0,0 +1,408 @@ +/* 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 nsTreeSanitizer_h_ +#define nsTreeSanitizer_h_ + +#include "nsAtom.h" +#include "nsHashKeys.h" +#include "nsHashtablesFwd.h" +#include "nsIPrincipal.h" +#include "nsTArray.h" +#include "nsTHashSet.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/dom/NameSpaceConstants.h" +#include "mozilla/dom/SanitizerBinding.h" + +class nsIContent; +class nsIGlobalObject; +class nsINode; + +namespace mozilla { +class DeclarationBlock; +class ErrorResult; +enum class StyleSanitizationKind : uint8_t; +} // namespace mozilla + +namespace mozilla::dom { +class DocumentFragment; +class Element; +class OwningStringOrSanitizerElementNameNamespace; +struct SanitizerAttribute; +} // namespace mozilla::dom + +/** + * See the documentation of nsIParserUtils::sanitize for documentation + * about the default behavior and the configuration options of this sanitizer. + */ +class nsTreeSanitizer { + public: + /** + * The constructor. + * + * @param aFlags Flags from nsIParserUtils + */ + explicit nsTreeSanitizer(uint32_t aFlags = 0); + + static void InitializeStatics(); + static void ReleaseStatics(); + + /** + * Sanitizes a disconnected DOM fragment freshly obtained from a parser. + * The fragment must have just come from a parser so that it can't have + * mutation event listeners set on it. + */ + void Sanitize(mozilla::dom::DocumentFragment* aFragment); + + /** + * Sanitizes a disconnected (not in a docshell) document freshly obtained + * from a parser. The document must not be embedded in a docshell and must + * not have had a chance to get mutation event listeners attached to it. + * The root element must be <html>. + */ + void Sanitize(mozilla::dom::Document* aDocument); + + /** + * Provides additional options for usage from the Web Sanitizer API + * which allows modifying the allow-list from above + */ + void WithWebSanitizerOptions(nsIGlobalObject* aGlobal, + const mozilla::dom::SanitizerConfig& aOptions, + mozilla::ErrorResult& aRv); + + /** + * Removes conditional CSS from this subtree. + */ + static void RemoveConditionalCSSFromSubtree(nsINode* aRoot); + + private: + /** + * Whether <style> and style="" are allowed. + */ + bool mAllowStyles; + + /** + * Whether comment nodes are allowed. + */ + bool mAllowComments; + + /** + * Whether HTML <font>, <center>, bgcolor="", etc., are dropped. + */ + bool mDropNonCSSPresentation; + + /** + * Whether to remove forms and form controls (excluding fieldset/legend). + */ + bool mDropForms; + + /** + * Whether only cid: embeds are allowed. + */ + bool mCidEmbedsOnly; + + /** + * Whether to drop <img>, <video>, <audio> and <svg>. + */ + bool mDropMedia; + + /** + * Whether we are sanitizing a full document (as opposed to a fragment). + */ + bool mFullDocument; + + /** + * Whether we should notify to the console for anything that's stripped. + */ + bool mLogRemovals; + + // WindowID used for logging removals. + uint64_t mInnerWindowID = 0; + + /** + * We have various tables of static atoms for elements and attributes. + */ + class AtomsTable : public nsTHashSet<const nsStaticAtom*> { + public: + explicit AtomsTable(uint32_t aLength) + : nsTHashSet<const nsStaticAtom*>(aLength) {} + + bool Contains(nsAtom* aAtom) { + // Because this table only contains static atoms, if aAtom isn't + // static we can immediately fail. + return aAtom->IsStatic() && GetEntry(aAtom->AsStatic()); + } + }; + + // The name of an element combined with its namespace. + class NamespaceAtom : public PLDHashEntryHdr { + public: + using KeyType = const NamespaceAtom&; + using KeyTypePointer = const NamespaceAtom*; + + explicit NamespaceAtom(KeyTypePointer aKey) + : mNamespaceID(aKey->mNamespaceID), mLocalName(aKey->mLocalName) {} + NamespaceAtom(int32_t aNamespaceID, RefPtr<nsAtom> aLocalName) + : mNamespaceID(aNamespaceID), mLocalName(std::move(aLocalName)) {} + NamespaceAtom(NamespaceAtom&&) = default; + ~NamespaceAtom() = default; + + bool KeyEquals(KeyTypePointer aKey) const { + return mNamespaceID == aKey->mNamespaceID && + mLocalName == aKey->mLocalName; + } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey) { + if (!aKey) { + return 0; + } + + return mozilla::HashGeneric(aKey->mNamespaceID, aKey->mLocalName.get()); + } + + enum { ALLOW_MEMMOVE = true }; + + private: + int32_t mNamespaceID = kNameSpaceID_None; + RefPtr<nsAtom> mLocalName; + }; + + using ElementName = NamespaceAtom; + using AttributeName = NamespaceAtom; + + using ElementNameSet = nsTHashSet<ElementName>; + // nullptr value (ElementNameSet) means all elements (*). + using AttributesToElementsMap = + nsTHashMap<AttributeName, mozilla::UniquePtr<ElementNameSet>>; + + void SanitizeChildren(nsINode* aRoot); + + /** + * Queries if an element must be replaced with its children. + * @param aNamespace the namespace of the element the question is about + * @param aLocal the local name of the element the question is about + * @return true if the element must be replaced with its children and + * false if the element is to be kept + */ + bool MustFlatten(int32_t aNamespace, nsAtom* aLocal); + bool MustFlattenForSanitizerAPI(int32_t aNamespace, nsAtom* aLocal); + + /** + * Queries if an element including its children must be removed. + * @param aNamespace the namespace of the element the question is about + * @param aLocal the local name of the element the question is about + * @param aElement the element node itself for inspecting attributes + * @return true if the element and its children must be removed and + * false if the element is to be kept + */ + bool MustPrune(int32_t aNamespace, nsAtom* aLocal, + mozilla::dom::Element* aElement); + bool MustPruneForSanitizerAPI(int32_t aNamespace, nsAtom* aLocal, + mozilla::dom::Element* aElement); + + /** + * Checks if a given local name (for an attribute) is on the given list + * of URL attribute names. + * @param aURLs the list of URL attribute names + * @param aLocalName the name to search on the list + * @return true if aLocalName is on the aURLs list and false otherwise + */ + bool IsURL(const nsStaticAtom* const* aURLs, nsAtom* aLocalName); + + /** + * Struct for what attributes and their values are allowed. + */ + struct AllowedAttributes { + // The whitelist of permitted local names to use. + AtomsTable* mNames = nullptr; + // The local names of URL-valued attributes for URL checking. + const nsStaticAtom* const* mURLs = nullptr; + // Whether XLink attributes are allowed. + bool mXLink = false; + // Whether the style attribute is allowed. + bool mStyle = false; + // Whether to leave the value of the src attribute unsanitized. + bool mDangerousSrc = false; + }; + + /** + * Removes dangerous attributes from the element. If the style attribute + * is allowed, its value is sanitized. The values of URL attributes are + * sanitized, except src isn't sanitized when it is allowed to remain + * potentially dangerous. + * + * @param aElement the element whose attributes should be sanitized + * @param aAllowed options for sanitizing attributes + */ + void SanitizeAttributes(mozilla::dom::Element* aElement, + AllowedAttributes aAllowed); + // Currently only used for the Sanitizer API. + bool MustDropAttribute(mozilla::dom::Element* aElement, + int32_t aAttrNamespace, nsAtom* aAttrLocalName); + bool MustDropFunkyAttribute(mozilla::dom::Element* aElement, + int32_t aAttrNamespace, nsAtom* aAttrLocalName); + + /** + * Remove the named URL attribute from the element if the URL fails a + * security check. + * + * @param aElement the element whose attribute to possibly modify + * @param aNamespace the namespace of the URL attribute + * @param aLocalName the local name of the URL attribute + * @param aFragmentsOnly allows same-document references only + * @return true if the attribute was removed and false otherwise + */ + bool SanitizeURL(mozilla::dom::Element* aElement, int32_t aNamespace, + nsAtom* aLocalName, bool aFragmentsOnly = false); + + /** + * Checks a style rule for the presence of the 'binding' CSS property and + * removes that property from the rule. + * + * @param aDeclaration The style declaration to check + * @return true if the rule was modified and false otherwise + */ + bool SanitizeStyleDeclaration(mozilla::DeclarationBlock* aDeclaration); + + /** + * Sanitizes an inline style element (an HTML or SVG <style>). + * + * Returns whether the style has changed. + */ + static bool SanitizeInlineStyle(mozilla::dom::Element*, + mozilla::StyleSanitizationKind); + + /** + * Removes all attributes from an element node. + */ + static void RemoveAllAttributes(mozilla::dom::Element* aElement); + + /** + * Removes all attributes from the descendants of an element but not from + * the element itself. + */ + static void RemoveAllAttributesFromDescendants(mozilla::dom::Element*); + + static bool MatchesElementName(ElementNameSet& aNames, int32_t aNamespace, + nsAtom* aLocalName); + static bool MatchesAttributeMatchList(AttributesToElementsMap& aMatchList, + mozilla::dom::Element& aElement, + int32_t aAttrNamespace, + nsAtom* aAttrLocalName); + + static mozilla::UniquePtr<ElementNameSet> ConvertElements( + const nsTArray<mozilla::dom::OwningStringOrSanitizerElementNamespace>& + aElements, + mozilla::ErrorResult& aRv); + + static mozilla::UniquePtr<ElementNameSet> ConvertElements( + const mozilla::dom::OwningStarOrStringOrSanitizerElementNamespaceSequence& + aElements, + mozilla::ErrorResult& aRv); + + static mozilla::UniquePtr<AttributesToElementsMap> ConvertAttributes( + const nsTArray<mozilla::dom::SanitizerAttribute>& aAttributes, + mozilla::ErrorResult& aRv); + + /** + * Log a Console Service message to indicate we removed something. + * If you pass an element and/or attribute, their information will + * be appended to the message. + * + * @param aMessage the basic message to log. + * @param aDocument the base document we're modifying + * (used for the error message) + * @param aElement optional, the element being removed or modified. + * @param aAttribute optional, the attribute being removed or modified. + */ + void LogMessage(const char* aMessage, mozilla::dom::Document* aDoc, + mozilla::dom::Element* aElement = nullptr, + nsAtom* aAttr = nullptr); + + /** + * The whitelist of HTML elements. + */ + static AtomsTable* sElementsHTML; + + /** + * The whitelist of non-presentational HTML attributes. + */ + static AtomsTable* sAttributesHTML; + + /** + * The whitelist of presentational HTML attributes. + */ + static AtomsTable* sPresAttributesHTML; + + /** + * The whitelist of SVG elements. + */ + static AtomsTable* sElementsSVG; + + /** + * The whitelist of SVG attributes. + */ + static AtomsTable* sAttributesSVG; + + /** + * The whitelist of SVG elements. + */ + static AtomsTable* sElementsMathML; + + /** + * The whitelist of MathML attributes. + */ + static AtomsTable* sAttributesMathML; + + /** + * The built-in baseline attribute allow list used by the Sanitizer API. + */ + static AtomsTable* sBaselineAttributeAllowlist; + + /** + * The built-in baseline element allow list used by the Sanitizer API. + */ + static AtomsTable* sBaselineElementAllowlist; + + /** + * The default configuration's attribute allow list used by the Sanitizer API. + */ + static AtomsTable* sDefaultConfigurationAttributeAllowlist; + + /** + * The default configuration's element allow list used by the Sanitizer API. + */ + static AtomsTable* sDefaultConfigurationElementAllowlist; + + /** + * Reusable null principal for URL checks. + */ + static nsIPrincipal* sNullPrincipal; + + // === Variables used to implement HTML Sanitizer API. == + + // This nsTreeSanitizer instance should behave like the Sanitizer API. + bool mIsForSanitizerAPI = false; + + bool mAllowCustomElements = false; + bool mAllowUnknownMarkup = false; + + // An allow-list of elements to keep. + mozilla::UniquePtr<ElementNameSet> mAllowElements; + + // A deny-list of elements to block. (aka flatten) + mozilla::UniquePtr<ElementNameSet> mBlockElements; + + // A deny-list of elements to drop. (aka prune) + mozilla::UniquePtr<ElementNameSet> mDropElements; + + // An allow-list of attributes to keep. + mozilla::UniquePtr<AttributesToElementsMap> mAllowAttributes; + + // A deny-list of attributes to drop. + mozilla::UniquePtr<AttributesToElementsMap> mDropAttributes; +}; + +#endif // nsTreeSanitizer_h_ |