diff options
author | Michal Klocek <michal.klocek@qt.io> | 2018-03-16 05:33:23 +0000 |
---|---|---|
committer | Michal Klocek <michal.klocek@qt.io> | 2018-06-06 12:44:11 +0000 |
commit | fa38dc29054d6895758bcc75e031a89597f3aaf6 (patch) | |
tree | a3081fc7fc76c2f6dd2038faa35c3ac6302462d6 | |
parent | df086394e015eca4bcaaac71a3da87837d9b8988 (diff) |
[Backport] CVE-2018-6145
HTML parser: Fix "HTML integration point" implementation in HTMLTreeBuilderSimulator.
HTMLTreeBuilderSimulator assumed only <foreignObject> as an HTML
integration point. This CL adds <annotation-xml>, <desc>, and SVG
<title>.
Bug: 805924
Reviewed-on: https://chromium-review.googlesource.com/964038
Change-Id: If99f8fdeb9b2b594925f04491d004709d8f774ad
Reviewed-by: Kai Koehne <kai.koehne@qt.io>
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
3 files changed, 92 insertions, 12 deletions
diff --git a/chromium/third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html-integration-point.html b/chromium/third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html-integration-point.html new file mode 100644 index 00000000000..be6b42d07d0 --- /dev/null +++ b/chromium/third_party/WebKit/LayoutTests/external/wpt/html/syntax/parsing/html-integration-point.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<link rel="help" href="https://html.spec.whatwg.org/multipage/parsing.html#tree-construction:html-integration-point"> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<math><annotation-xml id="point-1" encoding="text/html"><xmp></xmp><img></xmp></annotation-xml></math> +<math><annotation-xml id="point-2" encoding="application/xhtml+xml"><style></style><img></style></annotation-xml></math> +<svg><foreignObject id="point-3"><iframe></iframe><img></iframe></foreignObject></svg> +<svg><desc id="point-4"><noembed></noembed><img></noembed></desc></svg> +<svg><title id="point-5"><noframes></noframes><img></noframes></title></svg> + +<script> +function generate_test(id) { + return () => { + let point = document.querySelector('#' + id); + assert_not_equals(point.namespaceURI, 'http://www.w3.org/1999/xhtml'); + let rawTextElement = point.firstChild; + assert_equals(rawTextElement.namespaceURI, 'http://www.w3.org/1999/xhtml'); + assert_equals(rawTextElement.textContent.substr(0, 4), '<', + 'Entity references should not be decoded.'); + }; +} + +test(generate_test('point-1'), 'MathML annotation-xml with encoding=text/html should be an HTML integration point'); +test(generate_test('point-2'), 'MathML annotation-xml with encoding=application/xhtml+xml should be an HTML integration point'); +test(generate_test('point-3'), 'SVG foreignObject should be an HTML integration point'); +test(generate_test('point-4'), 'SVG desc should be an HTML integration point'); +test(generate_test('point-5'), 'SVG title should be an HTML integration point'); +</script> +</body> diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilderSimulator.cpp b/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilderSimulator.cpp index 34a3fbcdf96..1029c22a1af 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilderSimulator.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilderSimulator.cpp @@ -82,13 +82,6 @@ static bool TokenExitsForeignContent(const CompactHTMLToken& token) { token.GetAttributeItem(sizeAttr))); } -static bool TokenExitsSVG(const CompactHTMLToken& token) { - // FIXME: It's very fragile that we special case foreignObject here to be - // case-insensitive. - return DeprecatedEqualIgnoringCase(token.Data(), - SVGNames::foreignObjectTag.LocalName()); -} - static bool TokenExitsMath(const CompactHTMLToken& token) { // FIXME: This is copied from HTMLElementStack::isMathMLTextIntegrationPoint // and changed to use threadSafeMatch. @@ -148,10 +141,10 @@ HTMLTreeBuilderSimulator::SimulatedToken HTMLTreeBuilderSimulator::Simulate( namespace_stack_.push_back(kMathML); if (InForeignContent() && TokenExitsForeignContent(token)) namespace_stack_.pop_back(); - if ((namespace_stack_.back() == SVG && TokenExitsSVG(token)) || - (namespace_stack_.back() == kMathML && TokenExitsMath(token))) + if (IsHTMLIntegrationPointForStartTag(token) || + (namespace_stack_.back() == kMathML && TokenExitsMath(token))) { namespace_stack_.push_back(HTML); - if (!InForeignContent()) { + } else if (!InForeignContent()) { // FIXME: This is just a copy of Tokenizer::updateStateFor which uses // threadSafeMatches. if (ThreadSafeMatch(tag_name, textareaTag) || @@ -203,8 +196,7 @@ HTMLTreeBuilderSimulator::SimulatedToken HTMLTreeBuilderSimulator::Simulate( ThreadSafeMatch(tag_name, SVGNames::svgTag)) || (namespace_stack_.back() == kMathML && ThreadSafeMatch(tag_name, MathMLNames::mathTag)) || - (namespace_stack_.Contains(SVG) && namespace_stack_.back() == HTML && - TokenExitsSVG(token)) || + IsHTMLIntegrationPointForEndTag(token) || (namespace_stack_.Contains(kMathML) && namespace_stack_.back() == HTML && TokenExitsMath(token))) { namespace_stack_.pop_back(); @@ -226,4 +218,59 @@ HTMLTreeBuilderSimulator::SimulatedToken HTMLTreeBuilderSimulator::Simulate( return simulated_token; } +// https://html.spec.whatwg.org/multipage/parsing.html#html-integration-point +bool HTMLTreeBuilderSimulator::IsHTMLIntegrationPointForStartTag( + const CompactHTMLToken& token) const { + DCHECK(token.GetType() == HTMLToken::kStartTag) << token.GetType(); + + Namespace tokens_ns = namespace_stack_.back(); + const String& tag_name = token.Data(); + if (tokens_ns == kMathML) { + if (!ThreadSafeMatch(tag_name, MathMLNames::annotation_xmlTag)) + return false; + if (auto* encoding = token.GetAttributeItem(MathMLNames::encodingAttr)) { + return EqualIgnoringASCIICase(encoding->Value(), "text/html") || + EqualIgnoringASCIICase(encoding->Value(), "application/xhtml+xml"); + } + } else if (tokens_ns == SVG) { + // FIXME: It's very fragile that we special case foreignObject here to be + // case-insensitive. + if (DeprecatedEqualIgnoringCase(tag_name, + SVGNames::foreignObjectTag.LocalName())) + return true; + return ThreadSafeMatch(tag_name, SVGNames::descTag) || + ThreadSafeMatch(tag_name, SVGNames::titleTag); + } + return false; +} + +// https://html.spec.whatwg.org/multipage/parsing.html#html-integration-point +bool HTMLTreeBuilderSimulator::IsHTMLIntegrationPointForEndTag( + const CompactHTMLToken& token) const { + if (token.GetType() != HTMLToken::kEndTag) + return false; + + // If it's inside an HTML integration point, the top namespace is + // HTML, and its next namespace is not HTML. + if (namespace_stack_.back() != HTML) + return false; + if (namespace_stack_.size() < 2) + return false; + Namespace tokens_ns = namespace_stack_[namespace_stack_.size() - 2]; + + const String& tag_name = token.Data(); + if (tokens_ns == kMathML) + return ThreadSafeMatch(tag_name, MathMLNames::annotation_xmlTag); + if (tokens_ns == SVG) { + // FIXME: It's very fragile that we special case foreignObject here to be + // case-insensitive. + if (DeprecatedEqualIgnoringCase(tag_name, + SVGNames::foreignObjectTag.LocalName())) + return true; + return ThreadSafeMatch(tag_name, SVGNames::descTag) || + ThreadSafeMatch(tag_name, SVGNames::titleTag); + } + return false; +} + } // namespace blink diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilderSimulator.h b/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilderSimulator.h index 3aae7853f3a..2fd9f921ce3 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilderSimulator.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilderSimulator.h @@ -64,6 +64,8 @@ class CORE_EXPORT HTMLTreeBuilderSimulator { private: bool InForeignContent() const { return namespace_stack_.back() != HTML; } + bool IsHTMLIntegrationPointForStartTag(const CompactHTMLToken&) const; + bool IsHTMLIntegrationPointForEndTag(const CompactHTMLToken&) const; HTMLParserOptions options_; State namespace_stack_; |