1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsTreeSanitizer.h"
9 #include "mozilla/Algorithm.h"
10 #include "mozilla/ArrayUtils.h"
11 #include "mozilla/BindingStyleRule.h"
12 #include "mozilla/DeclarationBlock.h"
13 #include "mozilla/StyleSheetInlines.h"
14 #include "mozilla/UniquePtr.h"
15 #include "mozilla/css/Rule.h"
16 #include "mozilla/dom/SanitizerBinding.h"
17 #include "mozilla/dom/CSSRuleList.h"
18 #include "mozilla/dom/DocumentFragment.h"
19 #include "mozilla/dom/HTMLTemplateElement.h"
20 #include "mozilla/dom/SRIMetadata.h"
21 #include "mozilla/NullPrincipal.h"
23 #include "nsCSSPropertyID.h"
24 #include "nsHashtablesFwd.h"
26 #include "nsTHashtable.h"
27 #include "nsUnicharInputStream.h"
28 #include "nsAttrName.h"
29 #include "nsIScriptError.h"
30 #include "nsIScriptSecurityManager.h"
31 #include "nsNetUtil.h"
32 #include "nsComponentManagerUtils.h"
33 #include "nsContentUtils.h"
34 #include "nsIParserUtils.h"
35 #include "mozilla/dom/Document.h"
36 #include "nsQueryObject.h"
40 using namespace mozilla
;
41 using namespace mozilla::dom
;
44 // Thanks to Mark Pilgrim and Sam Ruby for the initial whitelist
46 const nsStaticAtom
* const kElementsHTML
[] = {
60 nsGkAtoms::blockquote
,
61 // body checked specially
84 nsGkAtoms::figcaption
,
95 // head checked specially
99 // html checked specially
146 // style checked specially
150 // template checked and traversed specially
156 // title checked specially
169 const nsStaticAtom
* const kAttributesHTML
[] = {
173 nsGkAtoms::acceptcharset
,
174 nsGkAtoms::accesskey
,
178 nsGkAtoms::autocomplete
,
179 nsGkAtoms::autofocus
,
191 nsGkAtoms::contenteditable
,
192 nsGkAtoms::contextmenu
,
195 nsGkAtoms::crossorigin
,
199 nsGkAtoms::draggable
,
212 nsGkAtoms::integrity
,
217 nsGkAtoms::itemscope
,
227 nsGkAtoms::maxlength
,
231 nsGkAtoms::minlength
,
236 nsGkAtoms::novalidate
,
241 nsGkAtoms::placeholder
,
242 nsGkAtoms::playbackrate
,
247 nsGkAtoms::radiogroup
,
262 nsGkAtoms::spellcheck
,
279 const nsStaticAtom
* const kPresAttributesHTML
[] = {
282 nsGkAtoms::background
,
285 nsGkAtoms::cellpadding
,
286 nsGkAtoms::cellspacing
,
292 nsGkAtoms::pointSize
,
300 // List of HTML attributes with URLs that the
301 // browser will fetch. Should be kept in sync with
302 // https://html.spec.whatwg.org/multipage/indices.html#attributes-3
303 const nsStaticAtom
* const kURLAttributesHTML
[] = {
310 nsGkAtoms::background
,
311 nsGkAtoms::formaction
,
319 const nsStaticAtom
* const kElementsSVG
[] = {
321 nsGkAtoms::circle
, // circle
322 nsGkAtoms::clipPath
, // clipPath
323 nsGkAtoms::colorProfile
, // color-profile
324 nsGkAtoms::cursor
, // cursor
325 nsGkAtoms::defs
, // defs
326 nsGkAtoms::desc
, // desc
327 nsGkAtoms::ellipse
, // ellipse
328 nsGkAtoms::elevation
, // elevation
329 nsGkAtoms::erode
, // erode
331 nsGkAtoms::exact
, // exact
332 nsGkAtoms::exponent
, // exponent
333 nsGkAtoms::feBlend
, // feBlend
334 nsGkAtoms::feColorMatrix
, // feColorMatrix
335 nsGkAtoms::feComponentTransfer
, // feComponentTransfer
336 nsGkAtoms::feComposite
, // feComposite
337 nsGkAtoms::feConvolveMatrix
, // feConvolveMatrix
338 nsGkAtoms::feDiffuseLighting
, // feDiffuseLighting
339 nsGkAtoms::feDisplacementMap
, // feDisplacementMap
340 nsGkAtoms::feDistantLight
, // feDistantLight
341 nsGkAtoms::feDropShadow
, // feDropShadow
342 nsGkAtoms::feFlood
, // feFlood
343 nsGkAtoms::feFuncA
, // feFuncA
344 nsGkAtoms::feFuncB
, // feFuncB
345 nsGkAtoms::feFuncG
, // feFuncG
346 nsGkAtoms::feFuncR
, // feFuncR
347 nsGkAtoms::feGaussianBlur
, // feGaussianBlur
348 nsGkAtoms::feImage
, // feImage
349 nsGkAtoms::feMerge
, // feMerge
350 nsGkAtoms::feMergeNode
, // feMergeNode
351 nsGkAtoms::feMorphology
, // feMorphology
352 nsGkAtoms::feOffset
, // feOffset
353 nsGkAtoms::fePointLight
, // fePointLight
354 nsGkAtoms::feSpecularLighting
, // feSpecularLighting
355 nsGkAtoms::feSpotLight
, // feSpotLight
356 nsGkAtoms::feTile
, // feTile
357 nsGkAtoms::feTurbulence
, // feTurbulence
358 nsGkAtoms::filter
, // filter
359 nsGkAtoms::font
, // font
360 nsGkAtoms::font_face
, // font-face
361 nsGkAtoms::font_face_format
, // font-face-format
362 nsGkAtoms::font_face_name
, // font-face-name
363 nsGkAtoms::font_face_src
, // font-face-src
364 nsGkAtoms::font_face_uri
, // font-face-uri
365 nsGkAtoms::foreignObject
, // foreignObject
368 nsGkAtoms::glyphRef
, // glyphRef
370 nsGkAtoms::image
, // image
371 nsGkAtoms::line
, // line
372 nsGkAtoms::linearGradient
, // linearGradient
373 nsGkAtoms::marker
, // marker
374 nsGkAtoms::mask
, // mask
375 nsGkAtoms::metadata
, // metadata
376 nsGkAtoms::missingGlyph
, // missingGlyph
377 nsGkAtoms::mpath
, // mpath
378 nsGkAtoms::path
, // path
379 nsGkAtoms::pattern
, // pattern
380 nsGkAtoms::polygon
, // polygon
381 nsGkAtoms::polyline
, // polyline
382 nsGkAtoms::radialGradient
, // radialGradient
383 nsGkAtoms::rect
, // rect
384 nsGkAtoms::stop
, // stop
385 nsGkAtoms::svg
, // svg
386 nsGkAtoms::svgSwitch
, // switch
387 nsGkAtoms::symbol
, // symbol
388 nsGkAtoms::text
, // text
389 nsGkAtoms::textPath
, // textPath
390 nsGkAtoms::title
, // title
391 nsGkAtoms::tref
, // tref
392 nsGkAtoms::tspan
, // tspan
393 nsGkAtoms::use
, // use
394 nsGkAtoms::view
, // view
398 constexpr const nsStaticAtom
* const kAttributesSVG
[] = {
400 nsGkAtoms::accumulate
, // accumulate
401 nsGkAtoms::additive
, // additive
402 nsGkAtoms::alignment_baseline
, // alignment-baseline
404 nsGkAtoms::amplitude
, // amplitude
407 nsGkAtoms::attributeName
, // attributeName
408 nsGkAtoms::attributeType
, // attributeType
409 nsGkAtoms::azimuth
, // azimuth
410 nsGkAtoms::baseFrequency
, // baseFrequency
411 nsGkAtoms::baseline_shift
, // baseline-shift
414 nsGkAtoms::begin
, // begin
415 nsGkAtoms::bias
, // bias
417 nsGkAtoms::calcMode
, // calcMode
419 nsGkAtoms::_class
, // class
420 nsGkAtoms::clip_path
, // clip-path
421 nsGkAtoms::clip_rule
, // clip-rule
422 nsGkAtoms::clipPathUnits
, // clipPathUnits
423 nsGkAtoms::color
, // color
424 nsGkAtoms::colorInterpolation
, // color-interpolation
425 nsGkAtoms::colorInterpolationFilters
, // color-interpolation-filters
426 nsGkAtoms::cursor
, // cursor
431 nsGkAtoms::diffuseConstant
, // diffuseConstant
432 nsGkAtoms::direction
, // direction
433 nsGkAtoms::display
, // display
434 nsGkAtoms::divisor
, // divisor
435 nsGkAtoms::dominant_baseline
, // dominant-baseline
436 nsGkAtoms::dur
, // dur
439 nsGkAtoms::edgeMode
, // edgeMode
440 nsGkAtoms::elevation
, // elevation
442 nsGkAtoms::end
, // end
443 nsGkAtoms::fill
, // fill
444 nsGkAtoms::fill_opacity
, // fill-opacity
445 nsGkAtoms::fill_rule
, // fill-rule
446 nsGkAtoms::filter
, // filter
447 nsGkAtoms::filterUnits
, // filterUnits
448 nsGkAtoms::flood_color
, // flood-color
449 nsGkAtoms::flood_opacity
, // flood-opacity
451 nsGkAtoms::font
, // font
452 nsGkAtoms::font_family
, // font-family
453 nsGkAtoms::font_size
, // font-size
454 nsGkAtoms::font_size_adjust
, // font-size-adjust
455 nsGkAtoms::font_stretch
, // font-stretch
456 nsGkAtoms::font_style
, // font-style
457 nsGkAtoms::font_variant
, // font-variant
458 nsGkAtoms::fontWeight
, // font-weight
459 nsGkAtoms::format
, // format
460 nsGkAtoms::from
, // from
467 // glyph-orientation-horizontal
468 // glyph-orientation-vertical
469 nsGkAtoms::gradientTransform
, // gradientTransform
470 nsGkAtoms::gradientUnits
, // gradientUnits
471 nsGkAtoms::height
, // height
478 nsGkAtoms::image_rendering
, // image-rendering
480 nsGkAtoms::in2
, // in2
481 nsGkAtoms::intercept
, // intercept
488 nsGkAtoms::kernelMatrix
, // kernelMatrix
489 nsGkAtoms::kernelUnitLength
, // kernelUnitLength
490 nsGkAtoms::keyPoints
, // keyPoints
491 nsGkAtoms::keySplines
, // keySplines
492 nsGkAtoms::keyTimes
, // keyTimes
493 nsGkAtoms::lang
, // lang
495 nsGkAtoms::letter_spacing
, // letter-spacing
496 nsGkAtoms::lighting_color
, // lighting-color
497 nsGkAtoms::limitingConeAngle
, // limitingConeAngle
499 nsGkAtoms::marker
, // marker
500 nsGkAtoms::marker_end
, // marker-end
501 nsGkAtoms::marker_mid
, // marker-mid
502 nsGkAtoms::marker_start
, // marker-start
503 nsGkAtoms::markerHeight
, // markerHeight
504 nsGkAtoms::markerUnits
, // markerUnits
505 nsGkAtoms::markerWidth
, // markerWidth
506 nsGkAtoms::mask
, // mask
507 nsGkAtoms::maskContentUnits
, // maskContentUnits
508 nsGkAtoms::maskUnits
, // maskUnits
510 nsGkAtoms::max
, // max
511 nsGkAtoms::media
, // media
512 nsGkAtoms::method
, // method
513 nsGkAtoms::min
, // min
514 nsGkAtoms::mode
, // mode
515 nsGkAtoms::name
, // name
516 nsGkAtoms::numOctaves
, // numOctaves
517 nsGkAtoms::offset
, // offset
518 nsGkAtoms::opacity
, // opacity
519 nsGkAtoms::_operator
, // operator
520 nsGkAtoms::order
, // order
521 nsGkAtoms::orient
, // orient
522 nsGkAtoms::orientation
, // orientation
525 // overline-thickness
526 nsGkAtoms::overflow
, // overflow
528 nsGkAtoms::path
, // path
529 nsGkAtoms::pathLength
, // pathLength
530 nsGkAtoms::patternContentUnits
, // patternContentUnits
531 nsGkAtoms::patternTransform
, // patternTransform
532 nsGkAtoms::patternUnits
, // patternUnits
533 nsGkAtoms::pointer_events
, // pointer-events XXX is this safe?
534 nsGkAtoms::points
, // points
535 nsGkAtoms::pointsAtX
, // pointsAtX
536 nsGkAtoms::pointsAtY
, // pointsAtY
537 nsGkAtoms::pointsAtZ
, // pointsAtZ
538 nsGkAtoms::preserveAlpha
, // preserveAlpha
539 nsGkAtoms::preserveAspectRatio
, // preserveAspectRatio
540 nsGkAtoms::primitiveUnits
, // primitiveUnits
542 nsGkAtoms::radius
, // radius
543 nsGkAtoms::refX
, // refX
544 nsGkAtoms::refY
, // refY
545 nsGkAtoms::repeatCount
, // repeatCount
546 nsGkAtoms::repeatDur
, // repeatDur
547 nsGkAtoms::requiredExtensions
, // requiredExtensions
548 nsGkAtoms::requiredFeatures
, // requiredFeatures
549 nsGkAtoms::restart
, // restart
550 nsGkAtoms::result
, // result
551 nsGkAtoms::rotate
, // rotate
554 nsGkAtoms::scale
, // scale
555 nsGkAtoms::seed
, // seed
556 nsGkAtoms::shape_rendering
, // shape-rendering
557 nsGkAtoms::slope
, // slope
558 nsGkAtoms::spacing
, // spacing
559 nsGkAtoms::specularConstant
, // specularConstant
560 nsGkAtoms::specularExponent
, // specularExponent
561 nsGkAtoms::spreadMethod
, // spreadMethod
562 nsGkAtoms::startOffset
, // startOffset
563 nsGkAtoms::stdDeviation
, // stdDeviation
566 nsGkAtoms::stitchTiles
, // stitchTiles
567 nsGkAtoms::stop_color
, // stop-color
568 nsGkAtoms::stop_opacity
, // stop-opacity
569 // strikethrough-position
570 // strikethrough-thickness
571 nsGkAtoms::string
, // string
572 nsGkAtoms::stroke
, // stroke
573 nsGkAtoms::stroke_dasharray
, // stroke-dasharray
574 nsGkAtoms::stroke_dashoffset
, // stroke-dashoffset
575 nsGkAtoms::stroke_linecap
, // stroke-linecap
576 nsGkAtoms::stroke_linejoin
, // stroke-linejoin
577 nsGkAtoms::stroke_miterlimit
, // stroke-miterlimit
578 nsGkAtoms::stroke_opacity
, // stroke-opacity
579 nsGkAtoms::stroke_width
, // stroke-width
580 nsGkAtoms::surfaceScale
, // surfaceScale
581 nsGkAtoms::systemLanguage
, // systemLanguage
582 nsGkAtoms::tableValues
, // tableValues
583 nsGkAtoms::target
, // target
584 nsGkAtoms::targetX
, // targetX
585 nsGkAtoms::targetY
, // targetY
586 nsGkAtoms::text_anchor
, // text-anchor
587 nsGkAtoms::text_decoration
, // text-decoration
589 nsGkAtoms::text_rendering
, // text-rendering
590 nsGkAtoms::title
, // title
592 nsGkAtoms::transform
, // transform
593 nsGkAtoms::transform_origin
, // transform-origin
594 nsGkAtoms::type
, // type
597 // underline-position
598 // underline-thickness
600 nsGkAtoms::unicode_bidi
, // unicode-bidi
607 nsGkAtoms::values
, // values
608 nsGkAtoms::vector_effect
, // vector-effect
612 nsGkAtoms::viewBox
, // viewBox
613 nsGkAtoms::viewTarget
, // viewTarget
614 nsGkAtoms::visibility
, // visibility
615 nsGkAtoms::width
, // width
617 nsGkAtoms::word_spacing
, // word-spacing
618 nsGkAtoms::writing_mode
, // writing-mode
623 nsGkAtoms::xChannelSelector
, // xChannelSelector
627 nsGkAtoms::yChannelSelector
, // yChannelSelector
629 nsGkAtoms::zoomAndPan
, // zoomAndPan
632 constexpr const nsStaticAtom
* const kURLAttributesSVG
[] = {nsGkAtoms::href
,
635 static_assert(AllOf(std::begin(kURLAttributesSVG
), std::end(kURLAttributesSVG
),
636 [](auto aURLAttributeSVG
) {
637 return AnyOf(std::begin(kAttributesSVG
),
638 std::end(kAttributesSVG
),
639 [&](auto aAttributeSVG
) {
640 return aAttributeSVG
== aURLAttributeSVG
;
644 const nsStaticAtom
* const kElementsMathML
[] = {
645 nsGkAtoms::abs_
, // abs
646 nsGkAtoms::_and
, // and
647 nsGkAtoms::annotation_
, // annotation
648 nsGkAtoms::annotation_xml_
, // annotation-xml
649 nsGkAtoms::apply_
, // apply
650 nsGkAtoms::approx_
, // approx
651 nsGkAtoms::arccos_
, // arccos
652 nsGkAtoms::arccosh_
, // arccosh
653 nsGkAtoms::arccot_
, // arccot
654 nsGkAtoms::arccoth_
, // arccoth
655 nsGkAtoms::arccsc_
, // arccsc
656 nsGkAtoms::arccsch_
, // arccsch
657 nsGkAtoms::arcsec_
, // arcsec
658 nsGkAtoms::arcsech_
, // arcsech
659 nsGkAtoms::arcsin_
, // arcsin
660 nsGkAtoms::arcsinh_
, // arcsinh
661 nsGkAtoms::arctan_
, // arctan
662 nsGkAtoms::arctanh_
, // arctanh
663 nsGkAtoms::arg_
, // arg
664 nsGkAtoms::bind_
, // bind
665 nsGkAtoms::bvar_
, // bvar
666 nsGkAtoms::card_
, // card
667 nsGkAtoms::cartesianproduct_
, // cartesianproduct
668 nsGkAtoms::cbytes_
, // cbytes
669 nsGkAtoms::ceiling
, // ceiling
670 nsGkAtoms::cerror_
, // cerror
671 nsGkAtoms::ci_
, // ci
672 nsGkAtoms::cn_
, // cn
673 nsGkAtoms::codomain_
, // codomain
674 nsGkAtoms::complexes_
, // complexes
675 nsGkAtoms::compose_
, // compose
676 nsGkAtoms::condition_
, // condition
677 nsGkAtoms::conjugate_
, // conjugate
678 nsGkAtoms::cos_
, // cos
679 nsGkAtoms::cosh_
, // cosh
680 nsGkAtoms::cot_
, // cot
681 nsGkAtoms::coth_
, // coth
682 nsGkAtoms::cs_
, // cs
683 nsGkAtoms::csc_
, // csc
684 nsGkAtoms::csch_
, // csch
685 nsGkAtoms::csymbol_
, // csymbol
686 nsGkAtoms::curl_
, // curl
687 nsGkAtoms::declare
, // declare
688 nsGkAtoms::degree_
, // degree
689 nsGkAtoms::determinant_
, // determinant
690 nsGkAtoms::diff_
, // diff
691 nsGkAtoms::divergence_
, // divergence
692 nsGkAtoms::divide_
, // divide
693 nsGkAtoms::domain_
, // domain
694 nsGkAtoms::domainofapplication_
, // domainofapplication
696 nsGkAtoms::emptyset_
, // emptyset
697 nsGkAtoms::eq_
, // eq
698 nsGkAtoms::equivalent_
, // equivalent
699 nsGkAtoms::eulergamma_
, // eulergamma
700 nsGkAtoms::exists_
, // exists
701 nsGkAtoms::exp_
, // exp
702 nsGkAtoms::exponentiale_
, // exponentiale
703 nsGkAtoms::factorial_
, // factorial
704 nsGkAtoms::factorof_
, // factorof
705 nsGkAtoms::_false
, // false
706 nsGkAtoms::floor
, // floor
707 nsGkAtoms::fn_
, // fn
708 nsGkAtoms::forall_
, // forall
709 nsGkAtoms::gcd_
, // gcd
710 nsGkAtoms::geq_
, // geq
711 nsGkAtoms::grad
, // grad
712 nsGkAtoms::gt_
, // gt
713 nsGkAtoms::ident_
, // ident
714 nsGkAtoms::image
, // image
715 nsGkAtoms::imaginary_
, // imaginary
716 nsGkAtoms::imaginaryi_
, // imaginaryi
717 nsGkAtoms::implies_
, // implies
719 nsGkAtoms::infinity
, // infinity
720 nsGkAtoms::int_
, // int
721 nsGkAtoms::integers_
, // integers
722 nsGkAtoms::intersect_
, // intersect
723 nsGkAtoms::interval_
, // interval
724 nsGkAtoms::inverse_
, // inverse
725 nsGkAtoms::lambda_
, // lambda
726 nsGkAtoms::laplacian_
, // laplacian
727 nsGkAtoms::lcm_
, // lcm
728 nsGkAtoms::leq_
, // leq
729 nsGkAtoms::limit_
, // limit
730 nsGkAtoms::list_
, // list
731 nsGkAtoms::ln_
, // ln
732 nsGkAtoms::log_
, // log
733 nsGkAtoms::logbase_
, // logbase
734 nsGkAtoms::lowlimit_
, // lowlimit
735 nsGkAtoms::lt_
, // lt
736 nsGkAtoms::maction_
, // maction
737 nsGkAtoms::maligngroup_
, // maligngroup
738 nsGkAtoms::malignmark_
, // malignmark
739 nsGkAtoms::math
, // math
740 nsGkAtoms::matrix
, // matrix
741 nsGkAtoms::matrixrow_
, // matrixrow
742 nsGkAtoms::max
, // max
743 nsGkAtoms::mean_
, // mean
744 nsGkAtoms::median_
, // median
745 nsGkAtoms::menclose_
, // menclose
746 nsGkAtoms::merror_
, // merror
747 nsGkAtoms::mfenced_
, // mfenced
748 nsGkAtoms::mfrac_
, // mfrac
749 nsGkAtoms::mglyph_
, // mglyph
750 nsGkAtoms::mi_
, // mi
751 nsGkAtoms::min
, // min
752 nsGkAtoms::minus_
, // minus
753 nsGkAtoms::mlabeledtr_
, // mlabeledtr
754 nsGkAtoms::mlongdiv_
, // mlongdiv
755 nsGkAtoms::mmultiscripts_
, // mmultiscripts
756 nsGkAtoms::mn_
, // mn
757 nsGkAtoms::mo_
, // mo
758 nsGkAtoms::mode
, // mode
759 nsGkAtoms::moment_
, // moment
760 nsGkAtoms::momentabout_
, // momentabout
761 nsGkAtoms::mover_
, // mover
762 nsGkAtoms::mpadded_
, // mpadded
763 nsGkAtoms::mphantom_
, // mphantom
764 nsGkAtoms::mprescripts_
, // mprescripts
765 nsGkAtoms::mroot_
, // mroot
766 nsGkAtoms::mrow_
, // mrow
767 nsGkAtoms::ms_
, // ms
768 nsGkAtoms::mscarries_
, // mscarries
769 nsGkAtoms::mscarry_
, // mscarry
770 nsGkAtoms::msgroup_
, // msgroup
771 nsGkAtoms::msline_
, // msline
772 nsGkAtoms::mspace_
, // mspace
773 nsGkAtoms::msqrt_
, // msqrt
774 nsGkAtoms::msrow_
, // msrow
775 nsGkAtoms::mstack_
, // mstack
776 nsGkAtoms::mstyle_
, // mstyle
777 nsGkAtoms::msub_
, // msub
778 nsGkAtoms::msubsup_
, // msubsup
779 nsGkAtoms::msup_
, // msup
780 nsGkAtoms::mtable_
, // mtable
781 nsGkAtoms::mtd_
, // mtd
782 nsGkAtoms::mtext_
, // mtext
783 nsGkAtoms::mtr_
, // mtr
784 nsGkAtoms::munder_
, // munder
785 nsGkAtoms::munderover_
, // munderover
786 nsGkAtoms::naturalnumbers_
, // naturalnumbers
787 nsGkAtoms::neq_
, // neq
788 nsGkAtoms::none
, // none
789 nsGkAtoms::_not
, // not
790 nsGkAtoms::notanumber_
, // notanumber
791 nsGkAtoms::note_
, // note
792 nsGkAtoms::notin_
, // notin
793 nsGkAtoms::notprsubset_
, // notprsubset
794 nsGkAtoms::notsubset_
, // notsubset
795 nsGkAtoms::_or
, // or
796 nsGkAtoms::otherwise
, // otherwise
797 nsGkAtoms::outerproduct_
, // outerproduct
798 nsGkAtoms::partialdiff_
, // partialdiff
799 nsGkAtoms::pi_
, // pi
800 nsGkAtoms::piece_
, // piece
801 nsGkAtoms::piecewise_
, // piecewise
802 nsGkAtoms::plus_
, // plus
803 nsGkAtoms::power_
, // power
804 nsGkAtoms::primes_
, // primes
805 nsGkAtoms::product_
, // product
806 nsGkAtoms::prsubset_
, // prsubset
807 nsGkAtoms::quotient_
, // quotient
808 nsGkAtoms::rationals_
, // rationals
809 nsGkAtoms::real_
, // real
810 nsGkAtoms::reals_
, // reals
811 nsGkAtoms::reln_
, // reln
812 nsGkAtoms::rem
, // rem
813 nsGkAtoms::root_
, // root
814 nsGkAtoms::scalarproduct_
, // scalarproduct
815 nsGkAtoms::sdev_
, // sdev
816 nsGkAtoms::sec_
, // sec
817 nsGkAtoms::sech_
, // sech
818 nsGkAtoms::selector_
, // selector
819 nsGkAtoms::semantics_
, // semantics
820 nsGkAtoms::sep_
, // sep
821 nsGkAtoms::set
, // set
822 nsGkAtoms::setdiff_
, // setdiff
823 nsGkAtoms::share_
, // share
824 nsGkAtoms::sin_
, // sin
825 nsGkAtoms::sinh_
, // sinh
826 nsGkAtoms::subset_
, // subset
827 nsGkAtoms::sum
, // sum
828 nsGkAtoms::tan_
, // tan
829 nsGkAtoms::tanh_
, // tanh
830 nsGkAtoms::tendsto_
, // tendsto
831 nsGkAtoms::times_
, // times
832 nsGkAtoms::transpose_
, // transpose
833 nsGkAtoms::_true
, // true
834 nsGkAtoms::union_
, // union
835 nsGkAtoms::uplimit_
, // uplimit
836 nsGkAtoms::variance_
, // variance
837 nsGkAtoms::vector_
, // vector
838 nsGkAtoms::vectorproduct_
, // vectorproduct
839 nsGkAtoms::xor_
, // xor
842 const nsStaticAtom
* const kAttributesMathML
[] = {
843 nsGkAtoms::accent_
, // accent
844 nsGkAtoms::accentunder_
, // accentunder
845 nsGkAtoms::actiontype_
, // actiontype
846 nsGkAtoms::align
, // align
847 nsGkAtoms::alignmentscope_
, // alignmentscope
848 nsGkAtoms::alt
, // alt
849 nsGkAtoms::altimg_
, // altimg
850 nsGkAtoms::altimg_height_
, // altimg-height
851 nsGkAtoms::altimg_valign_
, // altimg-valign
852 nsGkAtoms::altimg_width_
, // altimg-width
853 nsGkAtoms::background
, // background
854 nsGkAtoms::base
, // base
855 nsGkAtoms::bevelled_
, // bevelled
856 nsGkAtoms::cd_
, // cd
857 nsGkAtoms::cdgroup_
, // cdgroup
858 nsGkAtoms::charalign_
, // charalign
859 nsGkAtoms::close
, // close
860 nsGkAtoms::closure_
, // closure
861 nsGkAtoms::color
, // color
862 nsGkAtoms::columnalign_
, // columnalign
863 nsGkAtoms::columnalignment_
, // columnalignment
864 nsGkAtoms::columnlines_
, // columnlines
865 nsGkAtoms::columnspacing_
, // columnspacing
866 nsGkAtoms::columnspan_
, // columnspan
867 nsGkAtoms::columnwidth_
, // columnwidth
868 nsGkAtoms::crossout_
, // crossout
869 nsGkAtoms::decimalpoint_
, // decimalpoint
870 nsGkAtoms::definitionURL_
, // definitionURL
871 nsGkAtoms::denomalign_
, // denomalign
872 nsGkAtoms::depth_
, // depth
873 nsGkAtoms::dir
, // dir
874 nsGkAtoms::display
, // display
875 nsGkAtoms::displaystyle_
, // displaystyle
876 nsGkAtoms::edge_
, // edge
877 nsGkAtoms::encoding
, // encoding
878 nsGkAtoms::equalcolumns_
, // equalcolumns
879 nsGkAtoms::equalrows_
, // equalrows
880 nsGkAtoms::fence_
, // fence
881 nsGkAtoms::fontfamily_
, // fontfamily
882 nsGkAtoms::fontsize_
, // fontsize
883 nsGkAtoms::fontstyle_
, // fontstyle
884 nsGkAtoms::fontweight_
, // fontweight
885 nsGkAtoms::form
, // form
886 nsGkAtoms::frame
, // frame
887 nsGkAtoms::framespacing_
, // framespacing
888 nsGkAtoms::groupalign_
, // groupalign
889 nsGkAtoms::height
, // height
890 nsGkAtoms::href
, // href
892 nsGkAtoms::indentalign_
, // indentalign
893 nsGkAtoms::indentalignfirst_
, // indentalignfirst
894 nsGkAtoms::indentalignlast_
, // indentalignlast
895 nsGkAtoms::indentshift_
, // indentshift
896 nsGkAtoms::indentshiftfirst_
, // indentshiftfirst
897 nsGkAtoms::indenttarget_
, // indenttarget
898 nsGkAtoms::index
, // index
899 nsGkAtoms::integer
, // integer
900 nsGkAtoms::largeop_
, // largeop
901 nsGkAtoms::length
, // length
902 nsGkAtoms::linebreak_
, // linebreak
903 nsGkAtoms::linebreakmultchar_
, // linebreakmultchar
904 nsGkAtoms::linebreakstyle_
, // linebreakstyle
905 nsGkAtoms::linethickness_
, // linethickness
906 nsGkAtoms::location_
, // location
907 nsGkAtoms::longdivstyle_
, // longdivstyle
908 nsGkAtoms::lquote_
, // lquote
909 nsGkAtoms::lspace_
, // lspace
910 nsGkAtoms::ltr
, // ltr
911 nsGkAtoms::mathbackground_
, // mathbackground
912 nsGkAtoms::mathcolor_
, // mathcolor
913 nsGkAtoms::mathsize_
, // mathsize
914 nsGkAtoms::mathvariant_
, // mathvariant
915 nsGkAtoms::maxsize_
, // maxsize
916 nsGkAtoms::minlabelspacing_
, // minlabelspacing
917 nsGkAtoms::minsize_
, // minsize
918 nsGkAtoms::movablelimits_
, // movablelimits
919 nsGkAtoms::msgroup_
, // msgroup
920 nsGkAtoms::name
, // name
921 nsGkAtoms::newline
, // newline
922 nsGkAtoms::notation_
, // notation
923 nsGkAtoms::numalign_
, // numalign
924 nsGkAtoms::number
, // number
925 nsGkAtoms::open
, // open
926 nsGkAtoms::order
, // order
927 nsGkAtoms::other
, // other
928 nsGkAtoms::overflow
, // overflow
929 nsGkAtoms::position
, // position
930 nsGkAtoms::role
, // role
931 nsGkAtoms::rowalign_
, // rowalign
932 nsGkAtoms::rowlines_
, // rowlines
933 nsGkAtoms::rowspacing_
, // rowspacing
934 nsGkAtoms::rowspan
, // rowspan
935 nsGkAtoms::rquote_
, // rquote
936 nsGkAtoms::rspace_
, // rspace
937 nsGkAtoms::schemaLocation_
, // schemaLocation
938 nsGkAtoms::scriptlevel_
, // scriptlevel
939 nsGkAtoms::scriptminsize_
, // scriptminsize
940 nsGkAtoms::scriptsize_
, // scriptsize
941 nsGkAtoms::scriptsizemultiplier_
, // scriptsizemultiplier
942 nsGkAtoms::selection_
, // selection
943 nsGkAtoms::separator_
, // separator
944 nsGkAtoms::separators_
, // separators
945 nsGkAtoms::shift_
, // shift
946 nsGkAtoms::side_
, // side
947 nsGkAtoms::src
, // src
948 nsGkAtoms::stackalign_
, // stackalign
949 nsGkAtoms::stretchy_
, // stretchy
950 nsGkAtoms::subscriptshift_
, // subscriptshift
951 nsGkAtoms::superscriptshift_
, // superscriptshift
952 nsGkAtoms::symmetric_
, // symmetric
953 nsGkAtoms::type
, // type
954 nsGkAtoms::voffset_
, // voffset
955 nsGkAtoms::width
, // width
956 nsGkAtoms::xref_
, // xref
959 const nsStaticAtom
* const kURLAttributesMathML
[] = {
965 nsGkAtoms::definitionURL_
,
970 nsTreeSanitizer::AtomsTable
* nsTreeSanitizer::sElementsHTML
= nullptr;
971 nsTreeSanitizer::AtomsTable
* nsTreeSanitizer::sAttributesHTML
= nullptr;
972 nsTreeSanitizer::AtomsTable
* nsTreeSanitizer::sPresAttributesHTML
= nullptr;
973 nsTreeSanitizer::AtomsTable
* nsTreeSanitizer::sElementsSVG
= nullptr;
974 nsTreeSanitizer::AtomsTable
* nsTreeSanitizer::sAttributesSVG
= nullptr;
975 nsTreeSanitizer::AtomsTable
* nsTreeSanitizer::sElementsMathML
= nullptr;
976 nsTreeSanitizer::AtomsTable
* nsTreeSanitizer::sAttributesMathML
= nullptr;
977 nsIPrincipal
* nsTreeSanitizer::sNullPrincipal
= nullptr;
979 nsTreeSanitizer::nsTreeSanitizer(uint32_t aFlags
)
980 : mAllowStyles(aFlags
& nsIParserUtils::SanitizerAllowStyle
),
981 mAllowComments(aFlags
& nsIParserUtils::SanitizerAllowComments
),
982 mDropNonCSSPresentation(aFlags
&
983 nsIParserUtils::SanitizerDropNonCSSPresentation
),
984 mDropForms(aFlags
& nsIParserUtils::SanitizerDropForms
),
985 mCidEmbedsOnly(aFlags
& nsIParserUtils::SanitizerCidEmbedsOnly
),
986 mDropMedia(aFlags
& nsIParserUtils::SanitizerDropMedia
),
987 mFullDocument(false),
988 mLogRemovals(aFlags
& nsIParserUtils::SanitizerLogRemovals
),
989 mOnlyConditionalCSS(aFlags
&
990 nsIParserUtils::SanitizerRemoveOnlyConditionalCSS
) {
991 if (mCidEmbedsOnly
) {
992 // Sanitizing styles for external references is not supported.
993 mAllowStyles
= false;
996 mAllowedElements
= nullptr;
997 mBlockedElements
= nullptr;
999 if (!sElementsHTML
) {
1000 // Initialize lazily to avoid having to initialize at all if the user
1001 // doesn't paste HTML or load feeds.
1002 InitializeStatics();
1004 /* Ensure SanitizerRemoveOnlyConditionalCSS isn't combined with any
1005 * flags, except SanitizerLogRemovals. */
1006 MOZ_ASSERT(!mOnlyConditionalCSS
||
1008 (aFlags
& ~(nsIParserUtils::SanitizerRemoveOnlyConditionalCSS
|
1009 nsIParserUtils::SanitizerLogRemovals
)));
1012 bool nsTreeSanitizer::MustFlatten(int32_t aNamespace
, nsAtom
* aLocal
) {
1013 if (aNamespace
== kNameSpaceID_XHTML
) {
1014 if (mIsCustomized
) {
1015 // TODO(freddy): Make it work for other namespaces.
1016 // See https://github.com/WICG/sanitizer-api/issues/72
1017 return ((mAllowedElements
&& !mAllowedElements
->Contains(aLocal
)) ||
1018 ((mBlockedElements
&& mBlockedElements
->Contains(aLocal
))));
1020 if (mDropNonCSSPresentation
&&
1021 (nsGkAtoms::font
== aLocal
|| nsGkAtoms::center
== aLocal
)) {
1025 (nsGkAtoms::form
== aLocal
|| nsGkAtoms::input
== aLocal
||
1026 nsGkAtoms::option
== aLocal
|| nsGkAtoms::optgroup
== aLocal
)) {
1029 if (mFullDocument
&&
1030 (nsGkAtoms::title
== aLocal
|| nsGkAtoms::html
== aLocal
||
1031 nsGkAtoms::head
== aLocal
|| nsGkAtoms::body
== aLocal
)) {
1034 if (nsGkAtoms::_template
== aLocal
) {
1037 return !sElementsHTML
->Contains(aLocal
);
1039 if (aNamespace
== kNameSpaceID_SVG
) {
1040 if (mCidEmbedsOnly
|| mDropMedia
) {
1041 // Sanitizing CSS-based URL references inside SVG presentational
1042 // attributes is not supported, so flattening for cid: embed case.
1045 return !sElementsSVG
->Contains(aLocal
);
1047 if (aNamespace
== kNameSpaceID_MathML
) {
1048 return !sElementsMathML
->Contains(aLocal
);
1053 bool nsTreeSanitizer::IsURL(const nsStaticAtom
* const* aURLs
,
1054 nsAtom
* aLocalName
) {
1055 const nsStaticAtom
* atom
;
1056 while ((atom
= *aURLs
)) {
1057 if (atom
== aLocalName
) {
1065 bool nsTreeSanitizer::MustPrune(int32_t aNamespace
, nsAtom
* aLocal
,
1066 mozilla::dom::Element
* aElement
) {
1067 // To avoid attacks where a MathML script becomes something that gets
1068 // serialized in a way that it parses back as an HTML script, let's just
1069 // drop elements with the local name 'script' regardless of namespace.
1070 if (nsGkAtoms::script
== aLocal
) {
1073 if (aNamespace
== kNameSpaceID_XHTML
) {
1074 if (nsGkAtoms::title
== aLocal
&& !mFullDocument
) {
1075 // emulate the quirks of the old parser
1079 (nsGkAtoms::select
== aLocal
|| nsGkAtoms::button
== aLocal
||
1080 nsGkAtoms::datalist
== aLocal
)) {
1084 (nsGkAtoms::img
== aLocal
|| nsGkAtoms::video
== aLocal
||
1085 nsGkAtoms::audio
== aLocal
|| nsGkAtoms::source
== aLocal
)) {
1088 if (nsGkAtoms::meta
== aLocal
&&
1089 (aElement
->HasAttr(kNameSpaceID_None
, nsGkAtoms::charset
) ||
1090 aElement
->HasAttr(kNameSpaceID_None
, nsGkAtoms::httpEquiv
))) {
1091 // Throw away charset declarations even if they also have microdata
1092 // which they can't validly have.
1095 if (((!mFullDocument
&& nsGkAtoms::meta
== aLocal
) ||
1096 nsGkAtoms::link
== aLocal
) &&
1097 !(aElement
->HasAttr(kNameSpaceID_None
, nsGkAtoms::itemprop
) ||
1098 aElement
->HasAttr(kNameSpaceID_None
, nsGkAtoms::itemscope
))) {
1099 // emulate old behavior for non-Microdata <meta> and <link> presumably
1100 // in <head>. <meta> and <link> are whitelisted in order to avoid
1101 // corrupting Microdata when they appear in <body>. Note that
1102 // SanitizeAttributes() will remove the rel attribute from <link> and
1103 // the name attribute from <meta>.
1108 return nsGkAtoms::style
== aLocal
&& !(aNamespace
== kNameSpaceID_XHTML
||
1109 aNamespace
== kNameSpaceID_SVG
);
1111 if (nsGkAtoms::style
== aLocal
) {
1117 void nsTreeSanitizer::SanitizeStyleSheet(const nsAString
& aOriginal
,
1118 nsAString
& aSanitized
,
1119 Document
* aDocument
,
1121 aSanitized
.Truncate();
1123 NS_ConvertUTF16toUTF8
style(aOriginal
);
1124 RefPtr
<nsIReferrerInfo
> referrer
=
1125 ReferrerInfo::CreateForInternalCSSResources(aDocument
);
1127 MakeRefPtr
<URLExtraData
>(aBaseURI
, referrer
, aDocument
->NodePrincipal());
1128 auto sanitizationKind
= mOnlyConditionalCSS
1129 ? StyleSanitizationKind::NoConditionalRules
1130 : StyleSanitizationKind::Standard
;
1131 RefPtr
<RawServoStyleSheetContents
> contents
=
1132 Servo_StyleSheet_FromUTF8Bytes(
1133 /* loader = */ nullptr,
1134 /* stylesheet = */ nullptr,
1135 /* load_data = */ nullptr, &style
,
1136 css::SheetParsingMode::eAuthorSheetFeatures
, extraData
.get(),
1137 /* line_number_offset = */ 0, aDocument
->GetCompatibilityMode(),
1138 /* reusable_sheets = */ nullptr,
1139 /* use_counters = */ nullptr, StyleAllowImportRules::Yes
,
1140 sanitizationKind
, &aSanitized
)
1143 if (mLogRemovals
&& aSanitized
.Length() != aOriginal
.Length()) {
1144 LogMessage("Removed some rules and/or properties from stylesheet.",
1149 template <size_t Len
>
1150 static bool UTF16StringStartsWith(const char16_t
* aStr
, uint32_t aLength
,
1151 const char16_t (&aNeedle
)[Len
]) {
1152 MOZ_ASSERT(aNeedle
[Len
- 1] == '\0',
1153 "needle should be a UTF-16 encoded string literal");
1155 if (aLength
< Len
- 1) {
1158 for (size_t i
= 0; i
< Len
- 1; i
++) {
1159 if (aStr
[i
] != aNeedle
[i
]) {
1166 void nsTreeSanitizer::SanitizeAttributes(mozilla::dom::Element
* aElement
,
1167 AllowedAttributes aAllowed
) {
1168 int32_t ac
= (int)aElement
->GetAttrCount();
1170 for (int32_t i
= ac
- 1; i
>= 0; --i
) {
1171 const nsAttrName
* attrName
= aElement
->GetAttrNameAt(i
);
1172 int32_t attrNs
= attrName
->NamespaceID();
1173 RefPtr
<nsAtom
> attrLocal
= attrName
->LocalName();
1175 if (mIsCustomized
) {
1176 bool shouldRemove
= true;
1177 RefPtr
<nsAtom
> elemName
= aElement
->NodeInfo()->NameAtom();
1180 if (mAllowedAttributes
) {
1181 auto allowedElements
= mAllowedAttributes
->Lookup(attrLocal
);
1182 if (allowedElements
) {
1183 if (allowedElements
.Data()->Contains(elemName
) ||
1184 allowedElements
.Data()->Contains(nsGkAtoms::_asterisk
)) {
1185 shouldRemove
= false;
1189 // checking drop list last
1190 // i.e., if listd as both allowed and dropped, it will still be dropped
1191 if (mDroppedAttributes
) {
1192 auto dropElements
= mDroppedAttributes
->Lookup(attrLocal
);
1194 if (dropElements
.Data()->Contains(elemName
) ||
1195 dropElements
.Data()->Contains(nsGkAtoms::_asterisk
)) {
1196 shouldRemove
= true;
1201 aElement
->UnsetAttr(kNameSpaceID_None
, attrLocal
, false);
1202 // in case the attribute removal shuffled the attribute order, start
1205 i
= ac
; // i will be decremented immediately thanks to the for loop
1210 if (kNameSpaceID_None
== attrNs
) {
1211 if (aAllowed
.mStyle
&& nsGkAtoms::style
== attrLocal
) {
1214 if (aAllowed
.mDangerousSrc
&& nsGkAtoms::src
== attrLocal
) {
1217 if (IsURL(aAllowed
.mURLs
, attrLocal
)) {
1218 if (SanitizeURL(aElement
, attrNs
, attrLocal
)) {
1219 // in case the attribute removal shuffled the attribute order, start
1222 i
= ac
; // i will be decremented immediately thanks to the for loop
1225 // else fall through to see if there's another reason to drop this
1226 // attribute (in particular if the attribute is background="" on an
1229 if (!mDropNonCSSPresentation
&&
1230 (aAllowed
.mNames
== sAttributesHTML
) && // element is HTML
1231 sPresAttributesHTML
->Contains(attrLocal
)) {
1234 if (aAllowed
.mNames
->Contains(attrLocal
) &&
1235 !((attrLocal
== nsGkAtoms::rel
&&
1236 aElement
->IsHTMLElement(nsGkAtoms::link
)) ||
1237 (!mFullDocument
&& attrLocal
== nsGkAtoms::name
&&
1238 aElement
->IsHTMLElement(nsGkAtoms::meta
)))) {
1239 // name="" and rel="" are whitelisted, but treat them as blacklisted
1240 // for <meta name> (fragment case) and <link rel> (all cases) to avoid
1241 // document-wide metadata or styling overrides with non-conforming
1242 // <meta name itemprop> or
1243 // <link rel itemprop>
1246 const char16_t
* localStr
= attrLocal
->GetUTF16String();
1247 uint32_t localLen
= attrLocal
->GetLength();
1248 // Allow underscore to cater to the MCE editor library.
1249 // Allow data-* on SVG and MathML, too, as a forward-compat measure.
1250 // Allow aria-* on all for simplicity.
1251 if (UTF16StringStartsWith(localStr
, localLen
, u
"_") ||
1252 UTF16StringStartsWith(localStr
, localLen
, u
"data-") ||
1253 UTF16StringStartsWith(localStr
, localLen
, u
"aria-")) {
1257 } else if (kNameSpaceID_XML
== attrNs
) {
1258 if (nsGkAtoms::lang
== attrLocal
|| nsGkAtoms::space
== attrLocal
) {
1262 } else if (aAllowed
.mXLink
&& kNameSpaceID_XLink
== attrNs
) {
1263 if (nsGkAtoms::href
== attrLocal
) {
1264 if (SanitizeURL(aElement
, attrNs
, attrLocal
)) {
1265 // in case the attribute removal shuffled the attribute order, start
1268 i
= ac
; // i will be decremented immediately thanks to the for loop
1272 if (nsGkAtoms::type
== attrLocal
|| nsGkAtoms::title
== attrLocal
||
1273 nsGkAtoms::show
== attrLocal
|| nsGkAtoms::actuate
== attrLocal
) {
1278 aElement
->UnsetAttr(kNameSpaceID_None
, attrLocal
, false);
1280 LogMessage("Removed unsafe attribute.", aElement
->OwnerDoc(), aElement
,
1283 // in case the attribute removal shuffled the attribute order, start the
1286 i
= ac
; // i will be decremented immediately thanks to the for loop
1289 // If we've got HTML audio or video, add the controls attribute, because
1290 // otherwise the content is unplayable with scripts removed.
1291 if (aElement
->IsAnyOfHTMLElements(nsGkAtoms::video
, nsGkAtoms::audio
)) {
1292 aElement
->SetAttr(kNameSpaceID_None
, nsGkAtoms::controls
, u
""_ns
, false);
1296 bool nsTreeSanitizer::SanitizeURL(mozilla::dom::Element
* aElement
,
1297 int32_t aNamespace
, nsAtom
* aLocalName
) {
1299 aElement
->GetAttr(aNamespace
, aLocalName
, value
);
1301 // Get value and remove mandatory quotes
1302 static const char* kWhitespace
= "\n\r\t\b";
1303 const nsAString
& v
= nsContentUtils::TrimCharsInSet(kWhitespace
, value
);
1304 // Fragment-only url cannot be harmful.
1305 if (!v
.IsEmpty() && v
.First() == u
'#') {
1309 nsIScriptSecurityManager
* secMan
= nsContentUtils::GetSecurityManager();
1310 uint32_t flags
= nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL
;
1312 nsCOMPtr
<nsIURI
> attrURI
;
1314 NS_NewURI(getter_AddRefs(attrURI
), v
, nullptr, aElement
->GetBaseURI());
1315 if (NS_SUCCEEDED(rv
)) {
1316 if (mCidEmbedsOnly
&& kNameSpaceID_None
== aNamespace
) {
1317 if (nsGkAtoms::src
== aLocalName
|| nsGkAtoms::background
== aLocalName
) {
1318 // comm-central uses a hack that makes nsIURIs created with cid: specs
1319 // actually have an about:blank spec. Therefore, nsIURI facilities are
1320 // useless for cid: when comm-central code is participating.
1321 if (!(v
.Length() > 4 && (v
[0] == 'c' || v
[0] == 'C') &&
1322 (v
[1] == 'i' || v
[1] == 'I') && (v
[2] == 'd' || v
[2] == 'D') &&
1324 rv
= NS_ERROR_FAILURE
;
1326 } else if (nsGkAtoms::cdgroup_
== aLocalName
||
1327 nsGkAtoms::altimg_
== aLocalName
||
1328 nsGkAtoms::definitionURL_
== aLocalName
) {
1329 // Gecko doesn't fetch these now and shouldn't in the future, but
1330 // in case someone goofs with these in the future, let's drop them.
1331 rv
= NS_ERROR_FAILURE
;
1333 rv
= secMan
->CheckLoadURIWithPrincipal(sNullPrincipal
, attrURI
, flags
,
1337 rv
= secMan
->CheckLoadURIWithPrincipal(sNullPrincipal
, attrURI
, flags
, 0);
1340 if (NS_FAILED(rv
)) {
1341 aElement
->UnsetAttr(aNamespace
, aLocalName
, false);
1343 LogMessage("Removed unsafe URI from element attribute.",
1344 aElement
->OwnerDoc(), aElement
, aLocalName
);
1351 void nsTreeSanitizer::Sanitize(DocumentFragment
* aFragment
) {
1352 // If you want to relax these preconditions, be sure to check the code in
1353 // here that notifies / does not notify or that fires mutation events if
1355 MOZ_ASSERT(!aFragment
->IsInUncomposedDoc(), "The fragment is in doc?");
1357 mFullDocument
= false;
1358 SanitizeChildren(aFragment
);
1361 void nsTreeSanitizer::Sanitize(Document
* aDocument
) {
1362 // If you want to relax these preconditions, be sure to check the code in
1363 // here that notifies / does not notify or that fires mutation events if
1366 MOZ_ASSERT(!aDocument
->GetContainer(), "The document is in a shell.");
1367 RefPtr
<mozilla::dom::Element
> root
= aDocument
->GetRootElement();
1368 MOZ_ASSERT(root
->IsHTMLElement(nsGkAtoms::html
), "Not HTML root.");
1371 mFullDocument
= true;
1372 SanitizeChildren(aDocument
);
1375 void nsTreeSanitizer::SanitizeChildren(nsINode
* aRoot
) {
1376 nsIContent
* node
= aRoot
->GetFirstChild();
1378 if (node
->IsElement()) {
1379 mozilla::dom::Element
* elt
= node
->AsElement();
1380 mozilla::dom::NodeInfo
* nodeInfo
= node
->NodeInfo();
1381 nsAtom
* localName
= nodeInfo
->NameAtom();
1382 int32_t ns
= nodeInfo
->NamespaceID();
1384 if (!mOnlyConditionalCSS
&& MustPrune(ns
, localName
, elt
)) {
1386 LogMessage("Removing unsafe node.", elt
->OwnerDoc(), elt
);
1388 RemoveAllAttributes(elt
);
1389 nsIContent
* descendant
= node
;
1390 while ((descendant
= descendant
->GetNextNode(node
))) {
1391 if (descendant
->IsElement()) {
1392 RemoveAllAttributes(descendant
->AsElement());
1395 nsIContent
* next
= node
->GetNextNonChildNode(aRoot
);
1396 node
->RemoveFromParent();
1400 if (auto* templateEl
= HTMLTemplateElement::FromNode(elt
)) {
1401 // traverse into the DocFragment content attribute of template elements
1402 bool wasFullDocument
= mFullDocument
;
1403 mFullDocument
= false;
1404 RefPtr
<DocumentFragment
> frag
= templateEl
->Content();
1405 SanitizeChildren(frag
);
1406 mFullDocument
= wasFullDocument
;
1408 if (nsGkAtoms::style
== localName
) {
1409 // If !mOnlyConditionalCSS check the following condition:
1410 // If styles aren't allowed, style elements got pruned above. Even
1411 // if styles are allowed, non-HTML, non-SVG style elements got pruned
1413 NS_ASSERTION((ns
== kNameSpaceID_XHTML
|| ns
== kNameSpaceID_SVG
) ||
1414 mOnlyConditionalCSS
,
1415 "Should have only HTML or SVG here!");
1416 nsAutoString styleText
;
1417 nsContentUtils::GetNodeTextContent(node
, false, styleText
);
1419 nsAutoString sanitizedStyle
;
1420 SanitizeStyleSheet(styleText
, sanitizedStyle
, aRoot
->OwnerDoc(),
1421 node
->GetBaseURI());
1422 RemoveAllAttributesFromDescendants(elt
);
1423 nsContentUtils::SetNodeTextContent(node
, sanitizedStyle
, true);
1425 if (!mOnlyConditionalCSS
) {
1426 AllowedAttributes allowed
;
1427 allowed
.mStyle
= mAllowStyles
;
1428 if (ns
== kNameSpaceID_XHTML
) {
1429 allowed
.mNames
= sAttributesHTML
;
1430 allowed
.mURLs
= kURLAttributesHTML
;
1431 SanitizeAttributes(elt
, allowed
);
1433 allowed
.mNames
= sAttributesSVG
;
1434 allowed
.mURLs
= kURLAttributesSVG
;
1435 allowed
.mXLink
= true;
1436 SanitizeAttributes(elt
, allowed
);
1439 node
= node
->GetNextNonChildNode(aRoot
);
1442 if (!mOnlyConditionalCSS
&& MustFlatten(ns
, localName
)) {
1444 LogMessage("Flattening unsafe node (descendants are preserved).",
1445 elt
->OwnerDoc(), elt
);
1447 RemoveAllAttributes(elt
);
1448 nsCOMPtr
<nsIContent
> next
= node
->GetNextNode(aRoot
);
1449 nsCOMPtr
<nsIContent
> parent
= node
->GetParent();
1450 nsCOMPtr
<nsIContent
> child
; // Must keep the child alive during move
1452 while ((child
= node
->GetFirstChild())) {
1453 nsCOMPtr
<nsINode
> refNode
= node
;
1454 parent
->InsertBefore(*child
, refNode
, rv
);
1459 node
->RemoveFromParent();
1463 if (!mOnlyConditionalCSS
) {
1464 NS_ASSERTION(ns
== kNameSpaceID_XHTML
|| ns
== kNameSpaceID_SVG
||
1465 ns
== kNameSpaceID_MathML
,
1466 "Should have only HTML, MathML or SVG here!");
1467 AllowedAttributes allowed
;
1468 if (ns
== kNameSpaceID_XHTML
) {
1469 allowed
.mNames
= sAttributesHTML
;
1470 allowed
.mURLs
= kURLAttributesHTML
;
1471 allowed
.mStyle
= mAllowStyles
;
1472 allowed
.mDangerousSrc
=
1473 nsGkAtoms::img
== localName
&& !mCidEmbedsOnly
;
1474 SanitizeAttributes(elt
, allowed
);
1475 } else if (ns
== kNameSpaceID_SVG
) {
1476 allowed
.mNames
= sAttributesSVG
;
1477 allowed
.mURLs
= kURLAttributesSVG
;
1478 allowed
.mXLink
= true;
1479 allowed
.mStyle
= mAllowStyles
;
1480 SanitizeAttributes(elt
, allowed
);
1482 allowed
.mNames
= sAttributesMathML
;
1483 allowed
.mURLs
= kURLAttributesMathML
;
1484 allowed
.mXLink
= true;
1485 SanitizeAttributes(elt
, allowed
);
1488 node
= node
->GetNextNode(aRoot
);
1491 NS_ASSERTION(!node
->GetFirstChild(), "How come non-element node had kids?");
1492 nsIContent
* next
= node
->GetNextNonChildNode(aRoot
);
1493 if (!mOnlyConditionalCSS
&& (!mAllowComments
&& node
->IsComment())) {
1494 node
->RemoveFromParent();
1500 void nsTreeSanitizer::RemoveAllAttributes(Element
* aElement
) {
1501 const nsAttrName
* attrName
;
1502 while ((attrName
= aElement
->GetAttrNameAt(0))) {
1503 int32_t attrNs
= attrName
->NamespaceID();
1504 RefPtr
<nsAtom
> attrLocal
= attrName
->LocalName();
1505 aElement
->UnsetAttr(attrNs
, attrLocal
, false);
1509 void nsTreeSanitizer::RemoveAllAttributesFromDescendants(
1510 mozilla::dom::Element
* aElement
) {
1511 nsIContent
* node
= aElement
->GetFirstChild();
1513 if (node
->IsElement()) {
1514 mozilla::dom::Element
* elt
= node
->AsElement();
1515 RemoveAllAttributes(elt
);
1517 node
= node
->GetNextNode(aElement
);
1521 void nsTreeSanitizer::LogMessage(const char* aMessage
, Document
* aDoc
,
1522 Element
* aElement
, nsAtom
* aAttr
) {
1525 msg
.Assign(NS_ConvertASCIItoUTF16(aMessage
));
1527 msg
.Append(u
" Element: "_ns
+ aElement
->LocalName() + u
"."_ns
);
1530 msg
.Append(u
" Attribute: "_ns
+ nsDependentAtomString(aAttr
) + u
"."_ns
);
1533 nsContentUtils::ReportToConsoleNonLocalized(
1534 msg
, nsIScriptError::warningFlag
, "DOM"_ns
, aDoc
);
1538 void nsTreeSanitizer::InitializeStatics() {
1539 MOZ_ASSERT(!sElementsHTML
, "Initializing a second time.");
1541 sElementsHTML
= new AtomsTable(ArrayLength(kElementsHTML
));
1542 for (uint32_t i
= 0; kElementsHTML
[i
]; i
++) {
1543 sElementsHTML
->Insert(kElementsHTML
[i
]);
1546 sAttributesHTML
= new AtomsTable(ArrayLength(kAttributesHTML
));
1547 for (uint32_t i
= 0; kAttributesHTML
[i
]; i
++) {
1548 sAttributesHTML
->Insert(kAttributesHTML
[i
]);
1551 sPresAttributesHTML
= new AtomsTable(ArrayLength(kPresAttributesHTML
));
1552 for (uint32_t i
= 0; kPresAttributesHTML
[i
]; i
++) {
1553 sPresAttributesHTML
->Insert(kPresAttributesHTML
[i
]);
1556 sElementsSVG
= new AtomsTable(ArrayLength(kElementsSVG
));
1557 for (uint32_t i
= 0; kElementsSVG
[i
]; i
++) {
1558 sElementsSVG
->Insert(kElementsSVG
[i
]);
1561 sAttributesSVG
= new AtomsTable(ArrayLength(kAttributesSVG
));
1562 for (uint32_t i
= 0; kAttributesSVG
[i
]; i
++) {
1563 sAttributesSVG
->Insert(kAttributesSVG
[i
]);
1566 sElementsMathML
= new AtomsTable(ArrayLength(kElementsMathML
));
1567 for (uint32_t i
= 0; kElementsMathML
[i
]; i
++) {
1568 sElementsMathML
->Insert(kElementsMathML
[i
]);
1571 sAttributesMathML
= new AtomsTable(ArrayLength(kAttributesMathML
));
1572 for (uint32_t i
= 0; kAttributesMathML
[i
]; i
++) {
1573 sAttributesMathML
->Insert(kAttributesMathML
[i
]);
1576 nsCOMPtr
<nsIPrincipal
> principal
=
1577 NullPrincipal::CreateWithoutOriginAttributes();
1578 principal
.forget(&sNullPrincipal
);
1581 void nsTreeSanitizer::ReleaseStatics() {
1582 delete sElementsHTML
;
1583 sElementsHTML
= nullptr;
1585 delete sAttributesHTML
;
1586 sAttributesHTML
= nullptr;
1588 delete sPresAttributesHTML
;
1589 sPresAttributesHTML
= nullptr;
1591 delete sElementsSVG
;
1592 sElementsSVG
= nullptr;
1594 delete sAttributesSVG
;
1595 sAttributesSVG
= nullptr;
1597 delete sElementsMathML
;
1598 sElementsMathML
= nullptr;
1600 delete sAttributesMathML
;
1601 sAttributesMathML
= nullptr;
1603 NS_IF_RELEASE(sNullPrincipal
);
1606 void nsTreeSanitizer::WithWebSanitizerOptions(
1607 const mozilla::dom::SanitizerConfig
& aOptions
) {
1608 if (!aOptions
.IsAnyMemberPresent()) {
1611 if (aOptions
.mAllowComments
.WasPassed()) {
1612 mAllowComments
= aOptions
.mAllowComments
.Value();
1614 if (aOptions
.mAllowElements
.WasPassed()) {
1615 mIsCustomized
= true;
1616 const Sequence
<nsString
>& allowedElements
= aOptions
.mAllowElements
.Value();
1617 mAllowedElements
= MakeUnique
<DynamicAtomsTable
>(allowedElements
.Length());
1618 for (const nsString
& elem
: allowedElements
) {
1619 nsAutoString lowercaseElem
;
1620 nsContentUtils::ASCIIToLower(elem
, lowercaseElem
);
1621 RefPtr
<nsAtom
> elAsAtom
= NS_Atomize(lowercaseElem
);
1622 mAllowedElements
->Insert(elAsAtom
);
1625 mAllowedElements
= nullptr;
1627 if (aOptions
.mBlockElements
.WasPassed()) {
1628 mIsCustomized
= true;
1629 const Sequence
<nsString
>& blockedElements
= aOptions
.mBlockElements
.Value();
1630 mBlockedElements
= MakeUnique
<DynamicAtomsTable
>(blockedElements
.Length());
1631 for (const nsString
& elem
: blockedElements
) {
1632 nsAutoString lowercaseElem
;
1633 nsContentUtils::ASCIIToLower(elem
, lowercaseElem
);
1634 RefPtr
<nsAtom
> elAsAtom
= NS_Atomize(lowercaseElem
);
1635 mBlockedElements
->Insert(elAsAtom
);
1638 mBlockedElements
= nullptr;
1640 if (aOptions
.mAllowAttributes
.WasPassed()) {
1641 mIsCustomized
= true;
1642 const Record
<nsString
, Sequence
<nsString
>>& allowedAttributes
=
1643 aOptions
.mAllowAttributes
.Value();
1644 mAllowedAttributes
= MakeUnique
<
1645 nsTHashMap
<RefPtr
<nsAtom
>, mozilla::UniquePtr
<DynamicAtomsTable
>>>();
1647 for (const auto& entries
: allowedAttributes
.Entries()) {
1648 UniquePtr
<DynamicAtomsTable
> elems
=
1649 MakeUnique
<DynamicAtomsTable
>(allowedAttributes
.Entries().Length());
1650 for (const auto& elem
: entries
.mValue
) {
1651 nsAutoString lowercaseElem
;
1652 nsContentUtils::ASCIIToLower(elem
, lowercaseElem
);
1653 RefPtr
<nsAtom
> elAsAtom
= NS_Atomize(lowercaseElem
);
1654 elems
->Insert(elAsAtom
);
1656 nsAutoString attrName
;
1657 nsContentUtils::ASCIIToLower(entries
.mKey
, attrName
);
1658 RefPtr
<nsAtom
> attrAtom
= NS_Atomize(attrName
);
1659 mAllowedAttributes
->InsertOrUpdate(attrAtom
, std::move(elems
));
1662 mAllowedAttributes
= nullptr;
1664 if (aOptions
.mDropAttributes
.WasPassed()) {
1665 mIsCustomized
= true;
1666 const Record
<nsString
, Sequence
<nsString
>>& droppedAttributes
=
1667 aOptions
.mDropAttributes
.Value();
1668 mDroppedAttributes
= MakeUnique
<
1669 nsTHashMap
<RefPtr
<nsAtom
>, mozilla::UniquePtr
<DynamicAtomsTable
>>>();
1671 for (const auto& entries
: droppedAttributes
.Entries()) {
1672 UniquePtr
<DynamicAtomsTable
> elems
=
1673 MakeUnique
<DynamicAtomsTable
>(droppedAttributes
.Entries().Length());
1674 for (const auto& elem
: entries
.mValue
) {
1675 nsAutoString lowercaseElem
;
1676 nsContentUtils::ASCIIToLower(elem
, lowercaseElem
);
1677 RefPtr
<nsAtom
> elAsAtom
= NS_Atomize(lowercaseElem
);
1678 elems
->Insert(elAsAtom
);
1680 nsAutoString attrName
;
1681 nsContentUtils::ASCIIToLower(entries
.mKey
, attrName
);
1682 RefPtr
<nsAtom
> attrAtom
= NS_Atomize(attrName
);
1683 mDroppedAttributes
->InsertOrUpdate(attrAtom
, std::move(elems
));
1686 mDroppedAttributes
= nullptr;
1688 // TODO(freddy) Add handling of other keys in SanitizerConfig