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/ArrayUtils.h"
10 #include "mozilla/BindingStyleRule.h"
11 #include "mozilla/DeclarationBlock.h"
12 #include "mozilla/StyleSheetInlines.h"
13 #include "mozilla/css/Rule.h"
14 #include "mozilla/dom/CSSRuleList.h"
15 #include "mozilla/dom/DocumentFragment.h"
16 #include "mozilla/dom/SRIMetadata.h"
17 #include "mozilla/NullPrincipal.h"
18 #include "nsCSSPropertyID.h"
19 #include "nsUnicharInputStream.h"
20 #include "nsAttrName.h"
21 #include "nsIScriptError.h"
22 #include "nsIScriptSecurityManager.h"
23 #include "nsNetUtil.h"
24 #include "nsComponentManagerUtils.h"
25 #include "nsContentUtils.h"
26 #include "nsIParserUtils.h"
27 #include "mozilla/dom/Document.h"
28 #include "nsQueryObject.h"
30 using namespace mozilla
;
31 using namespace mozilla::dom
;
34 // Thanks to Mark Pilgrim and Sam Ruby for the initial whitelist
36 const nsStaticAtom
* const kElementsHTML
[] = {
50 nsGkAtoms::blockquote
,
51 // body checked specially
72 nsGkAtoms::figcaption
,
83 // head checked specially
87 // html checked specially
131 // style checked specially
140 // title checked specially
153 const nsStaticAtom
* const kAttributesHTML
[] = {
157 nsGkAtoms::acceptcharset
,
158 nsGkAtoms::accesskey
,
162 nsGkAtoms::autocomplete
,
163 nsGkAtoms::autofocus
,
175 nsGkAtoms::contenteditable
,
176 nsGkAtoms::contextmenu
,
179 nsGkAtoms::crossorigin
,
183 nsGkAtoms::draggable
,
196 nsGkAtoms::integrity
,
201 nsGkAtoms::itemscope
,
211 nsGkAtoms::maxlength
,
215 nsGkAtoms::minlength
,
220 nsGkAtoms::novalidate
,
225 nsGkAtoms::placeholder
,
226 nsGkAtoms::playbackrate
,
231 nsGkAtoms::radiogroup
,
246 nsGkAtoms::spellcheck
,
263 const nsStaticAtom
* const kPresAttributesHTML
[] = {
266 nsGkAtoms::background
,
269 nsGkAtoms::cellpadding
,
270 nsGkAtoms::cellspacing
,
276 nsGkAtoms::pointSize
,
284 const nsStaticAtom
* const kURLAttributesHTML
[] = {
291 nsGkAtoms::background
,
296 const nsStaticAtom
* const kElementsSVG
[] = {
298 nsGkAtoms::circle
, // circle
299 nsGkAtoms::clipPath
, // clipPath
300 nsGkAtoms::colorProfile
, // color-profile
301 nsGkAtoms::cursor
, // cursor
302 nsGkAtoms::defs
, // defs
303 nsGkAtoms::desc
, // desc
304 nsGkAtoms::ellipse
, // ellipse
305 nsGkAtoms::elevation
, // elevation
306 nsGkAtoms::erode
, // erode
308 nsGkAtoms::exact
, // exact
309 nsGkAtoms::exponent
, // exponent
310 nsGkAtoms::feBlend
, // feBlend
311 nsGkAtoms::feColorMatrix
, // feColorMatrix
312 nsGkAtoms::feComponentTransfer
, // feComponentTransfer
313 nsGkAtoms::feComposite
, // feComposite
314 nsGkAtoms::feConvolveMatrix
, // feConvolveMatrix
315 nsGkAtoms::feDiffuseLighting
, // feDiffuseLighting
316 nsGkAtoms::feDisplacementMap
, // feDisplacementMap
317 nsGkAtoms::feDistantLight
, // feDistantLight
318 nsGkAtoms::feDropShadow
, // feDropShadow
319 nsGkAtoms::feFlood
, // feFlood
320 nsGkAtoms::feFuncA
, // feFuncA
321 nsGkAtoms::feFuncB
, // feFuncB
322 nsGkAtoms::feFuncG
, // feFuncG
323 nsGkAtoms::feFuncR
, // feFuncR
324 nsGkAtoms::feGaussianBlur
, // feGaussianBlur
325 nsGkAtoms::feImage
, // feImage
326 nsGkAtoms::feMerge
, // feMerge
327 nsGkAtoms::feMergeNode
, // feMergeNode
328 nsGkAtoms::feMorphology
, // feMorphology
329 nsGkAtoms::feOffset
, // feOffset
330 nsGkAtoms::fePointLight
, // fePointLight
331 nsGkAtoms::feSpecularLighting
, // feSpecularLighting
332 nsGkAtoms::feSpotLight
, // feSpotLight
333 nsGkAtoms::feTile
, // feTile
334 nsGkAtoms::feTurbulence
, // feTurbulence
335 nsGkAtoms::filter
, // filter
336 nsGkAtoms::font
, // font
337 nsGkAtoms::font_face
, // font-face
338 nsGkAtoms::font_face_format
, // font-face-format
339 nsGkAtoms::font_face_name
, // font-face-name
340 nsGkAtoms::font_face_src
, // font-face-src
341 nsGkAtoms::font_face_uri
, // font-face-uri
342 nsGkAtoms::foreignObject
, // foreignObject
345 nsGkAtoms::glyphRef
, // glyphRef
347 nsGkAtoms::image
, // image
348 nsGkAtoms::line
, // line
349 nsGkAtoms::linearGradient
, // linearGradient
350 nsGkAtoms::marker
, // marker
351 nsGkAtoms::mask
, // mask
352 nsGkAtoms::metadata
, // metadata
353 nsGkAtoms::missingGlyph
, // missingGlyph
354 nsGkAtoms::mpath
, // mpath
355 nsGkAtoms::path
, // path
356 nsGkAtoms::pattern
, // pattern
357 nsGkAtoms::polygon
, // polygon
358 nsGkAtoms::polyline
, // polyline
359 nsGkAtoms::radialGradient
, // radialGradient
360 nsGkAtoms::rect
, // rect
361 nsGkAtoms::stop
, // stop
362 nsGkAtoms::svg
, // svg
363 nsGkAtoms::svgSwitch
, // switch
364 nsGkAtoms::symbol
, // symbol
365 nsGkAtoms::text
, // text
366 nsGkAtoms::textPath
, // textPath
367 nsGkAtoms::title
, // title
368 nsGkAtoms::tref
, // tref
369 nsGkAtoms::tspan
, // tspan
370 nsGkAtoms::use
, // use
371 nsGkAtoms::view
, // view
375 const nsStaticAtom
* const kAttributesSVG
[] = {
377 nsGkAtoms::accumulate
, // accumulate
378 nsGkAtoms::additive
, // additive
379 nsGkAtoms::alignment_baseline
, // alignment-baseline
381 nsGkAtoms::amplitude
, // amplitude
384 nsGkAtoms::attributeName
, // attributeName
385 nsGkAtoms::attributeType
, // attributeType
386 nsGkAtoms::azimuth
, // azimuth
387 nsGkAtoms::baseFrequency
, // baseFrequency
388 nsGkAtoms::baseline_shift
, // baseline-shift
391 nsGkAtoms::begin
, // begin
392 nsGkAtoms::bias
, // bias
394 nsGkAtoms::calcMode
, // calcMode
396 nsGkAtoms::_class
, // class
397 nsGkAtoms::clip_path
, // clip-path
398 nsGkAtoms::clip_rule
, // clip-rule
399 nsGkAtoms::clipPathUnits
, // clipPathUnits
400 nsGkAtoms::color
, // color
401 nsGkAtoms::colorInterpolation
, // color-interpolation
402 nsGkAtoms::colorInterpolationFilters
, // color-interpolation-filters
403 nsGkAtoms::cursor
, // cursor
408 nsGkAtoms::diffuseConstant
, // diffuseConstant
409 nsGkAtoms::direction
, // direction
410 nsGkAtoms::display
, // display
411 nsGkAtoms::divisor
, // divisor
412 nsGkAtoms::dominant_baseline
, // dominant-baseline
413 nsGkAtoms::dur
, // dur
416 nsGkAtoms::edgeMode
, // edgeMode
417 nsGkAtoms::elevation
, // elevation
419 nsGkAtoms::end
, // end
420 nsGkAtoms::fill
, // fill
421 nsGkAtoms::fill_opacity
, // fill-opacity
422 nsGkAtoms::fill_rule
, // fill-rule
423 nsGkAtoms::filter
, // filter
424 nsGkAtoms::filterUnits
, // filterUnits
425 nsGkAtoms::flood_color
, // flood-color
426 nsGkAtoms::flood_opacity
, // flood-opacity
428 nsGkAtoms::font
, // font
429 nsGkAtoms::font_family
, // font-family
430 nsGkAtoms::font_size
, // font-size
431 nsGkAtoms::font_size_adjust
, // font-size-adjust
432 nsGkAtoms::font_stretch
, // font-stretch
433 nsGkAtoms::font_style
, // font-style
434 nsGkAtoms::font_variant
, // font-variant
435 nsGkAtoms::fontWeight
, // font-weight
436 nsGkAtoms::format
, // format
437 nsGkAtoms::from
, // from
444 // glyph-orientation-horizontal
445 // glyph-orientation-vertical
446 nsGkAtoms::gradientTransform
, // gradientTransform
447 nsGkAtoms::gradientUnits
, // gradientUnits
448 nsGkAtoms::height
, // height
454 nsGkAtoms::image_rendering
, // image-rendering
456 nsGkAtoms::in2
, // in2
457 nsGkAtoms::intercept
, // intercept
464 nsGkAtoms::kernelMatrix
, // kernelMatrix
465 nsGkAtoms::kernelUnitLength
, // kernelUnitLength
466 nsGkAtoms::keyPoints
, // keyPoints
467 nsGkAtoms::keySplines
, // keySplines
468 nsGkAtoms::keyTimes
, // keyTimes
469 nsGkAtoms::lang
, // lang
471 nsGkAtoms::letter_spacing
, // letter-spacing
472 nsGkAtoms::lighting_color
, // lighting-color
473 nsGkAtoms::limitingConeAngle
, // limitingConeAngle
475 nsGkAtoms::marker
, // marker
476 nsGkAtoms::marker_end
, // marker-end
477 nsGkAtoms::marker_mid
, // marker-mid
478 nsGkAtoms::marker_start
, // marker-start
479 nsGkAtoms::markerHeight
, // markerHeight
480 nsGkAtoms::markerUnits
, // markerUnits
481 nsGkAtoms::markerWidth
, // markerWidth
482 nsGkAtoms::mask
, // mask
483 nsGkAtoms::maskContentUnits
, // maskContentUnits
484 nsGkAtoms::maskUnits
, // maskUnits
486 nsGkAtoms::max
, // max
487 nsGkAtoms::media
, // media
488 nsGkAtoms::method
, // method
489 nsGkAtoms::min
, // min
490 nsGkAtoms::mode
, // mode
491 nsGkAtoms::name
, // name
492 nsGkAtoms::numOctaves
, // numOctaves
493 nsGkAtoms::offset
, // offset
494 nsGkAtoms::opacity
, // opacity
495 nsGkAtoms::_operator
, // operator
496 nsGkAtoms::order
, // order
497 nsGkAtoms::orient
, // orient
498 nsGkAtoms::orientation
, // orientation
501 // overline-thickness
502 nsGkAtoms::overflow
, // overflow
504 nsGkAtoms::path
, // path
505 nsGkAtoms::pathLength
, // pathLength
506 nsGkAtoms::patternContentUnits
, // patternContentUnits
507 nsGkAtoms::patternTransform
, // patternTransform
508 nsGkAtoms::patternUnits
, // patternUnits
509 nsGkAtoms::pointer_events
, // pointer-events XXX is this safe?
510 nsGkAtoms::points
, // points
511 nsGkAtoms::pointsAtX
, // pointsAtX
512 nsGkAtoms::pointsAtY
, // pointsAtY
513 nsGkAtoms::pointsAtZ
, // pointsAtZ
514 nsGkAtoms::preserveAlpha
, // preserveAlpha
515 nsGkAtoms::preserveAspectRatio
, // preserveAspectRatio
516 nsGkAtoms::primitiveUnits
, // primitiveUnits
518 nsGkAtoms::radius
, // radius
519 nsGkAtoms::refX
, // refX
520 nsGkAtoms::refY
, // refY
521 nsGkAtoms::repeatCount
, // repeatCount
522 nsGkAtoms::repeatDur
, // repeatDur
523 nsGkAtoms::requiredExtensions
, // requiredExtensions
524 nsGkAtoms::requiredFeatures
, // requiredFeatures
525 nsGkAtoms::restart
, // restart
526 nsGkAtoms::result
, // result
527 nsGkAtoms::rotate
, // rotate
530 nsGkAtoms::scale
, // scale
531 nsGkAtoms::seed
, // seed
532 nsGkAtoms::shape_rendering
, // shape-rendering
533 nsGkAtoms::slope
, // slope
534 nsGkAtoms::spacing
, // spacing
535 nsGkAtoms::specularConstant
, // specularConstant
536 nsGkAtoms::specularExponent
, // specularExponent
537 nsGkAtoms::spreadMethod
, // spreadMethod
538 nsGkAtoms::startOffset
, // startOffset
539 nsGkAtoms::stdDeviation
, // stdDeviation
542 nsGkAtoms::stitchTiles
, // stitchTiles
543 nsGkAtoms::stop_color
, // stop-color
544 nsGkAtoms::stop_opacity
, // stop-opacity
545 // strikethrough-position
546 // strikethrough-thickness
547 nsGkAtoms::string
, // string
548 nsGkAtoms::stroke
, // stroke
549 nsGkAtoms::stroke_dasharray
, // stroke-dasharray
550 nsGkAtoms::stroke_dashoffset
, // stroke-dashoffset
551 nsGkAtoms::stroke_linecap
, // stroke-linecap
552 nsGkAtoms::stroke_linejoin
, // stroke-linejoin
553 nsGkAtoms::stroke_miterlimit
, // stroke-miterlimit
554 nsGkAtoms::stroke_opacity
, // stroke-opacity
555 nsGkAtoms::stroke_width
, // stroke-width
556 nsGkAtoms::surfaceScale
, // surfaceScale
557 nsGkAtoms::systemLanguage
, // systemLanguage
558 nsGkAtoms::tableValues
, // tableValues
559 nsGkAtoms::target
, // target
560 nsGkAtoms::targetX
, // targetX
561 nsGkAtoms::targetY
, // targetY
562 nsGkAtoms::text_anchor
, // text-anchor
563 nsGkAtoms::text_decoration
, // text-decoration
565 nsGkAtoms::text_rendering
, // text-rendering
566 nsGkAtoms::title
, // title
568 nsGkAtoms::transform
, // transform
569 nsGkAtoms::type
, // type
572 // underline-position
573 // underline-thickness
575 nsGkAtoms::unicode_bidi
, // unicode-bidi
582 nsGkAtoms::values
, // values
583 nsGkAtoms::vector_effect
, // vector-effect
587 nsGkAtoms::viewBox
, // viewBox
588 nsGkAtoms::viewTarget
, // viewTarget
589 nsGkAtoms::visibility
, // visibility
590 nsGkAtoms::width
, // width
592 nsGkAtoms::word_spacing
, // word-spacing
593 nsGkAtoms::writing_mode
, // writing-mode
598 nsGkAtoms::xChannelSelector
, // xChannelSelector
602 nsGkAtoms::yChannelSelector
, // yChannelSelector
604 nsGkAtoms::zoomAndPan
, // zoomAndPan
607 const nsStaticAtom
* const kURLAttributesSVG
[] = {nsGkAtoms::href
, nullptr};
609 const nsStaticAtom
* const kElementsMathML
[] = {
610 nsGkAtoms::abs_
, // abs
611 nsGkAtoms::_and
, // and
612 nsGkAtoms::annotation_
, // annotation
613 nsGkAtoms::annotation_xml_
, // annotation-xml
614 nsGkAtoms::apply_
, // apply
615 nsGkAtoms::approx_
, // approx
616 nsGkAtoms::arccos_
, // arccos
617 nsGkAtoms::arccosh_
, // arccosh
618 nsGkAtoms::arccot_
, // arccot
619 nsGkAtoms::arccoth_
, // arccoth
620 nsGkAtoms::arccsc_
, // arccsc
621 nsGkAtoms::arccsch_
, // arccsch
622 nsGkAtoms::arcsec_
, // arcsec
623 nsGkAtoms::arcsech_
, // arcsech
624 nsGkAtoms::arcsin_
, // arcsin
625 nsGkAtoms::arcsinh_
, // arcsinh
626 nsGkAtoms::arctan_
, // arctan
627 nsGkAtoms::arctanh_
, // arctanh
628 nsGkAtoms::arg_
, // arg
629 nsGkAtoms::bind_
, // bind
630 nsGkAtoms::bvar_
, // bvar
631 nsGkAtoms::card_
, // card
632 nsGkAtoms::cartesianproduct_
, // cartesianproduct
633 nsGkAtoms::cbytes_
, // cbytes
634 nsGkAtoms::ceiling
, // ceiling
635 nsGkAtoms::cerror_
, // cerror
636 nsGkAtoms::ci_
, // ci
637 nsGkAtoms::cn_
, // cn
638 nsGkAtoms::codomain_
, // codomain
639 nsGkAtoms::complexes_
, // complexes
640 nsGkAtoms::compose_
, // compose
641 nsGkAtoms::condition_
, // condition
642 nsGkAtoms::conjugate_
, // conjugate
643 nsGkAtoms::cos_
, // cos
644 nsGkAtoms::cosh_
, // cosh
645 nsGkAtoms::cot_
, // cot
646 nsGkAtoms::coth_
, // coth
647 nsGkAtoms::cs_
, // cs
648 nsGkAtoms::csc_
, // csc
649 nsGkAtoms::csch_
, // csch
650 nsGkAtoms::csymbol_
, // csymbol
651 nsGkAtoms::curl_
, // curl
652 nsGkAtoms::declare
, // declare
653 nsGkAtoms::degree_
, // degree
654 nsGkAtoms::determinant_
, // determinant
655 nsGkAtoms::diff_
, // diff
656 nsGkAtoms::divergence_
, // divergence
657 nsGkAtoms::divide_
, // divide
658 nsGkAtoms::domain_
, // domain
659 nsGkAtoms::domainofapplication_
, // domainofapplication
661 nsGkAtoms::emptyset_
, // emptyset
662 nsGkAtoms::eq_
, // eq
663 nsGkAtoms::equivalent_
, // equivalent
664 nsGkAtoms::eulergamma_
, // eulergamma
665 nsGkAtoms::exists_
, // exists
666 nsGkAtoms::exp_
, // exp
667 nsGkAtoms::exponentiale_
, // exponentiale
668 nsGkAtoms::factorial_
, // factorial
669 nsGkAtoms::factorof_
, // factorof
670 nsGkAtoms::_false
, // false
671 nsGkAtoms::floor
, // floor
672 nsGkAtoms::fn_
, // fn
673 nsGkAtoms::forall_
, // forall
674 nsGkAtoms::gcd_
, // gcd
675 nsGkAtoms::geq_
, // geq
676 nsGkAtoms::grad
, // grad
677 nsGkAtoms::gt_
, // gt
678 nsGkAtoms::ident_
, // ident
679 nsGkAtoms::image
, // image
680 nsGkAtoms::imaginary_
, // imaginary
681 nsGkAtoms::imaginaryi_
, // imaginaryi
682 nsGkAtoms::implies_
, // implies
684 nsGkAtoms::infinity
, // infinity
685 nsGkAtoms::int_
, // int
686 nsGkAtoms::integers_
, // integers
687 nsGkAtoms::intersect_
, // intersect
688 nsGkAtoms::interval_
, // interval
689 nsGkAtoms::inverse_
, // inverse
690 nsGkAtoms::lambda_
, // lambda
691 nsGkAtoms::laplacian_
, // laplacian
692 nsGkAtoms::lcm_
, // lcm
693 nsGkAtoms::leq_
, // leq
694 nsGkAtoms::limit_
, // limit
695 nsGkAtoms::list_
, // list
696 nsGkAtoms::ln_
, // ln
697 nsGkAtoms::log_
, // log
698 nsGkAtoms::logbase_
, // logbase
699 nsGkAtoms::lowlimit_
, // lowlimit
700 nsGkAtoms::lt_
, // lt
701 nsGkAtoms::maction_
, // maction
702 nsGkAtoms::maligngroup_
, // maligngroup
703 nsGkAtoms::malignmark_
, // malignmark
704 nsGkAtoms::math
, // math
705 nsGkAtoms::matrix
, // matrix
706 nsGkAtoms::matrixrow_
, // matrixrow
707 nsGkAtoms::max
, // max
708 nsGkAtoms::mean_
, // mean
709 nsGkAtoms::median_
, // median
710 nsGkAtoms::menclose_
, // menclose
711 nsGkAtoms::merror_
, // merror
712 nsGkAtoms::mfenced_
, // mfenced
713 nsGkAtoms::mfrac_
, // mfrac
714 nsGkAtoms::mglyph_
, // mglyph
715 nsGkAtoms::mi_
, // mi
716 nsGkAtoms::min
, // min
717 nsGkAtoms::minus_
, // minus
718 nsGkAtoms::mlabeledtr_
, // mlabeledtr
719 nsGkAtoms::mlongdiv_
, // mlongdiv
720 nsGkAtoms::mmultiscripts_
, // mmultiscripts
721 nsGkAtoms::mn_
, // mn
722 nsGkAtoms::mo_
, // mo
723 nsGkAtoms::mode
, // mode
724 nsGkAtoms::moment_
, // moment
725 nsGkAtoms::momentabout_
, // momentabout
726 nsGkAtoms::mover_
, // mover
727 nsGkAtoms::mpadded_
, // mpadded
728 nsGkAtoms::mphantom_
, // mphantom
729 nsGkAtoms::mprescripts_
, // mprescripts
730 nsGkAtoms::mroot_
, // mroot
731 nsGkAtoms::mrow_
, // mrow
732 nsGkAtoms::ms_
, // ms
733 nsGkAtoms::mscarries_
, // mscarries
734 nsGkAtoms::mscarry_
, // mscarry
735 nsGkAtoms::msgroup_
, // msgroup
736 nsGkAtoms::msline_
, // msline
737 nsGkAtoms::mspace_
, // mspace
738 nsGkAtoms::msqrt_
, // msqrt
739 nsGkAtoms::msrow_
, // msrow
740 nsGkAtoms::mstack_
, // mstack
741 nsGkAtoms::mstyle_
, // mstyle
742 nsGkAtoms::msub_
, // msub
743 nsGkAtoms::msubsup_
, // msubsup
744 nsGkAtoms::msup_
, // msup
745 nsGkAtoms::mtable_
, // mtable
746 nsGkAtoms::mtd_
, // mtd
747 nsGkAtoms::mtext_
, // mtext
748 nsGkAtoms::mtr_
, // mtr
749 nsGkAtoms::munder_
, // munder
750 nsGkAtoms::munderover_
, // munderover
751 nsGkAtoms::naturalnumbers_
, // naturalnumbers
752 nsGkAtoms::neq_
, // neq
753 nsGkAtoms::none
, // none
754 nsGkAtoms::_not
, // not
755 nsGkAtoms::notanumber_
, // notanumber
756 nsGkAtoms::note_
, // note
757 nsGkAtoms::notin_
, // notin
758 nsGkAtoms::notprsubset_
, // notprsubset
759 nsGkAtoms::notsubset_
, // notsubset
760 nsGkAtoms::_or
, // or
761 nsGkAtoms::otherwise
, // otherwise
762 nsGkAtoms::outerproduct_
, // outerproduct
763 nsGkAtoms::partialdiff_
, // partialdiff
764 nsGkAtoms::pi_
, // pi
765 nsGkAtoms::piece_
, // piece
766 nsGkAtoms::piecewise_
, // piecewise
767 nsGkAtoms::plus_
, // plus
768 nsGkAtoms::power_
, // power
769 nsGkAtoms::primes_
, // primes
770 nsGkAtoms::product_
, // product
771 nsGkAtoms::prsubset_
, // prsubset
772 nsGkAtoms::quotient_
, // quotient
773 nsGkAtoms::rationals_
, // rationals
774 nsGkAtoms::real_
, // real
775 nsGkAtoms::reals_
, // reals
776 nsGkAtoms::reln_
, // reln
777 nsGkAtoms::rem
, // rem
778 nsGkAtoms::root_
, // root
779 nsGkAtoms::scalarproduct_
, // scalarproduct
780 nsGkAtoms::sdev_
, // sdev
781 nsGkAtoms::sec_
, // sec
782 nsGkAtoms::sech_
, // sech
783 nsGkAtoms::selector_
, // selector
784 nsGkAtoms::semantics_
, // semantics
785 nsGkAtoms::sep_
, // sep
786 nsGkAtoms::set
, // set
787 nsGkAtoms::setdiff_
, // setdiff
788 nsGkAtoms::share_
, // share
789 nsGkAtoms::sin_
, // sin
790 nsGkAtoms::sinh_
, // sinh
791 nsGkAtoms::subset_
, // subset
792 nsGkAtoms::sum
, // sum
793 nsGkAtoms::tan_
, // tan
794 nsGkAtoms::tanh_
, // tanh
795 nsGkAtoms::tendsto_
, // tendsto
796 nsGkAtoms::times_
, // times
797 nsGkAtoms::transpose_
, // transpose
798 nsGkAtoms::_true
, // true
799 nsGkAtoms::union_
, // union
800 nsGkAtoms::uplimit_
, // uplimit
801 nsGkAtoms::variance_
, // variance
802 nsGkAtoms::vector_
, // vector
803 nsGkAtoms::vectorproduct_
, // vectorproduct
804 nsGkAtoms::xor_
, // xor
807 const nsStaticAtom
* const kAttributesMathML
[] = {
808 nsGkAtoms::accent_
, // accent
809 nsGkAtoms::accentunder_
, // accentunder
810 nsGkAtoms::actiontype_
, // actiontype
811 nsGkAtoms::align
, // align
812 nsGkAtoms::alignmentscope_
, // alignmentscope
813 nsGkAtoms::alt
, // alt
814 nsGkAtoms::altimg_
, // altimg
815 nsGkAtoms::altimg_height_
, // altimg-height
816 nsGkAtoms::altimg_valign_
, // altimg-valign
817 nsGkAtoms::altimg_width_
, // altimg-width
818 nsGkAtoms::background
, // background
819 nsGkAtoms::base
, // base
820 nsGkAtoms::bevelled_
, // bevelled
821 nsGkAtoms::cd_
, // cd
822 nsGkAtoms::cdgroup_
, // cdgroup
823 nsGkAtoms::charalign_
, // charalign
824 nsGkAtoms::close
, // close
825 nsGkAtoms::closure_
, // closure
826 nsGkAtoms::color
, // color
827 nsGkAtoms::columnalign_
, // columnalign
828 nsGkAtoms::columnalignment_
, // columnalignment
829 nsGkAtoms::columnlines_
, // columnlines
830 nsGkAtoms::columnspacing_
, // columnspacing
831 nsGkAtoms::columnspan_
, // columnspan
832 nsGkAtoms::columnwidth_
, // columnwidth
833 nsGkAtoms::crossout_
, // crossout
834 nsGkAtoms::decimalpoint_
, // decimalpoint
835 nsGkAtoms::definitionURL_
, // definitionURL
836 nsGkAtoms::denomalign_
, // denomalign
837 nsGkAtoms::depth_
, // depth
838 nsGkAtoms::dir
, // dir
839 nsGkAtoms::display
, // display
840 nsGkAtoms::displaystyle_
, // displaystyle
841 nsGkAtoms::edge_
, // edge
842 nsGkAtoms::encoding
, // encoding
843 nsGkAtoms::equalcolumns_
, // equalcolumns
844 nsGkAtoms::equalrows_
, // equalrows
845 nsGkAtoms::fence_
, // fence
846 nsGkAtoms::fontfamily_
, // fontfamily
847 nsGkAtoms::fontsize_
, // fontsize
848 nsGkAtoms::fontstyle_
, // fontstyle
849 nsGkAtoms::fontweight_
, // fontweight
850 nsGkAtoms::form
, // form
851 nsGkAtoms::frame
, // frame
852 nsGkAtoms::framespacing_
, // framespacing
853 nsGkAtoms::groupalign_
, // groupalign
854 nsGkAtoms::height
, // height
855 nsGkAtoms::href
, // href
857 nsGkAtoms::indentalign_
, // indentalign
858 nsGkAtoms::indentalignfirst_
, // indentalignfirst
859 nsGkAtoms::indentalignlast_
, // indentalignlast
860 nsGkAtoms::indentshift_
, // indentshift
861 nsGkAtoms::indentshiftfirst_
, // indentshiftfirst
862 nsGkAtoms::indenttarget_
, // indenttarget
863 nsGkAtoms::index
, // index
864 nsGkAtoms::integer
, // integer
865 nsGkAtoms::largeop_
, // largeop
866 nsGkAtoms::length
, // length
867 nsGkAtoms::linebreak_
, // linebreak
868 nsGkAtoms::linebreakmultchar_
, // linebreakmultchar
869 nsGkAtoms::linebreakstyle_
, // linebreakstyle
870 nsGkAtoms::linethickness_
, // linethickness
871 nsGkAtoms::location_
, // location
872 nsGkAtoms::longdivstyle_
, // longdivstyle
873 nsGkAtoms::lquote_
, // lquote
874 nsGkAtoms::lspace_
, // lspace
875 nsGkAtoms::ltr
, // ltr
876 nsGkAtoms::mathbackground_
, // mathbackground
877 nsGkAtoms::mathcolor_
, // mathcolor
878 nsGkAtoms::mathsize_
, // mathsize
879 nsGkAtoms::mathvariant_
, // mathvariant
880 nsGkAtoms::maxsize_
, // maxsize
881 nsGkAtoms::minlabelspacing_
, // minlabelspacing
882 nsGkAtoms::minsize_
, // minsize
883 nsGkAtoms::movablelimits_
, // movablelimits
884 nsGkAtoms::msgroup_
, // msgroup
885 nsGkAtoms::name
, // name
886 nsGkAtoms::newline
, // newline
887 nsGkAtoms::notation_
, // notation
888 nsGkAtoms::numalign_
, // numalign
889 nsGkAtoms::number
, // number
890 nsGkAtoms::open
, // open
891 nsGkAtoms::order
, // order
892 nsGkAtoms::other
, // other
893 nsGkAtoms::overflow
, // overflow
894 nsGkAtoms::position
, // position
895 nsGkAtoms::role
, // role
896 nsGkAtoms::rowalign_
, // rowalign
897 nsGkAtoms::rowlines_
, // rowlines
898 nsGkAtoms::rowspacing_
, // rowspacing
899 nsGkAtoms::rowspan
, // rowspan
900 nsGkAtoms::rquote_
, // rquote
901 nsGkAtoms::rspace_
, // rspace
902 nsGkAtoms::schemaLocation_
, // schemaLocation
903 nsGkAtoms::scriptlevel_
, // scriptlevel
904 nsGkAtoms::scriptminsize_
, // scriptminsize
905 nsGkAtoms::scriptsize_
, // scriptsize
906 nsGkAtoms::scriptsizemultiplier_
, // scriptsizemultiplier
907 nsGkAtoms::selection_
, // selection
908 nsGkAtoms::separator_
, // separator
909 nsGkAtoms::separators_
, // separators
910 nsGkAtoms::shift_
, // shift
911 nsGkAtoms::side_
, // side
912 nsGkAtoms::src
, // src
913 nsGkAtoms::stackalign_
, // stackalign
914 nsGkAtoms::stretchy_
, // stretchy
915 nsGkAtoms::subscriptshift_
, // subscriptshift
916 nsGkAtoms::superscriptshift_
, // superscriptshift
917 nsGkAtoms::symmetric_
, // symmetric
918 nsGkAtoms::type
, // type
919 nsGkAtoms::voffset_
, // voffset
920 nsGkAtoms::width
, // width
921 nsGkAtoms::xref_
, // xref
924 const nsStaticAtom
* const kURLAttributesMathML
[] = {
930 nsGkAtoms::definitionURL_
,
935 nsTreeSanitizer::AtomsTable
* nsTreeSanitizer::sElementsHTML
= nullptr;
936 nsTreeSanitizer::AtomsTable
* nsTreeSanitizer::sAttributesHTML
= nullptr;
937 nsTreeSanitizer::AtomsTable
* nsTreeSanitizer::sPresAttributesHTML
= nullptr;
938 nsTreeSanitizer::AtomsTable
* nsTreeSanitizer::sElementsSVG
= nullptr;
939 nsTreeSanitizer::AtomsTable
* nsTreeSanitizer::sAttributesSVG
= nullptr;
940 nsTreeSanitizer::AtomsTable
* nsTreeSanitizer::sElementsMathML
= nullptr;
941 nsTreeSanitizer::AtomsTable
* nsTreeSanitizer::sAttributesMathML
= nullptr;
942 nsIPrincipal
* nsTreeSanitizer::sNullPrincipal
= nullptr;
944 nsTreeSanitizer::nsTreeSanitizer(uint32_t aFlags
)
945 : mAllowStyles(aFlags
& nsIParserUtils::SanitizerAllowStyle
),
946 mAllowComments(aFlags
& nsIParserUtils::SanitizerAllowComments
),
947 mDropNonCSSPresentation(aFlags
&
948 nsIParserUtils::SanitizerDropNonCSSPresentation
),
949 mDropForms(aFlags
& nsIParserUtils::SanitizerDropForms
),
950 mCidEmbedsOnly(aFlags
& nsIParserUtils::SanitizerCidEmbedsOnly
),
951 mDropMedia(aFlags
& nsIParserUtils::SanitizerDropMedia
),
952 mFullDocument(false),
953 mLogRemovals(aFlags
& nsIParserUtils::SanitizerLogRemovals
) {
954 if (mCidEmbedsOnly
) {
955 // Sanitizing styles for external references is not supported.
956 mAllowStyles
= false;
958 if (!sElementsHTML
) {
959 // Initialize lazily to avoid having to initialize at all if the user
960 // doesn't paste HTML or load feeds.
965 bool nsTreeSanitizer::MustFlatten(int32_t aNamespace
, nsAtom
* aLocal
) {
966 if (aNamespace
== kNameSpaceID_XHTML
) {
967 if (mDropNonCSSPresentation
&&
968 (nsGkAtoms::font
== aLocal
|| nsGkAtoms::center
== aLocal
)) {
972 (nsGkAtoms::form
== aLocal
|| nsGkAtoms::input
== aLocal
||
973 nsGkAtoms::keygen
== aLocal
|| nsGkAtoms::option
== aLocal
||
974 nsGkAtoms::optgroup
== aLocal
)) {
978 (nsGkAtoms::title
== aLocal
|| nsGkAtoms::html
== aLocal
||
979 nsGkAtoms::head
== aLocal
|| nsGkAtoms::body
== aLocal
)) {
982 return !sElementsHTML
->Contains(aLocal
);
984 if (aNamespace
== kNameSpaceID_SVG
) {
985 if (mCidEmbedsOnly
|| mDropMedia
) {
986 // Sanitizing CSS-based URL references inside SVG presentational
987 // attributes is not supported, so flattening for cid: embed case.
990 return !sElementsSVG
->Contains(aLocal
);
992 if (aNamespace
== kNameSpaceID_MathML
) {
993 return !sElementsMathML
->Contains(aLocal
);
998 bool nsTreeSanitizer::IsURL(const nsStaticAtom
* const* aURLs
,
999 nsAtom
* aLocalName
) {
1000 const nsStaticAtom
* atom
;
1001 while ((atom
= *aURLs
)) {
1002 if (atom
== aLocalName
) {
1010 bool nsTreeSanitizer::MustPrune(int32_t aNamespace
, nsAtom
* aLocal
,
1011 mozilla::dom::Element
* aElement
) {
1012 // To avoid attacks where a MathML script becomes something that gets
1013 // serialized in a way that it parses back as an HTML script, let's just
1014 // drop elements with the local name 'script' regardless of namespace.
1015 if (nsGkAtoms::script
== aLocal
) {
1018 if (aNamespace
== kNameSpaceID_XHTML
) {
1019 if (nsGkAtoms::title
== aLocal
&& !mFullDocument
) {
1020 // emulate the quirks of the old parser
1024 (nsGkAtoms::select
== aLocal
|| nsGkAtoms::button
== aLocal
||
1025 nsGkAtoms::datalist
== aLocal
)) {
1029 (nsGkAtoms::img
== aLocal
|| nsGkAtoms::video
== aLocal
||
1030 nsGkAtoms::audio
== aLocal
|| nsGkAtoms::source
== aLocal
)) {
1033 if (nsGkAtoms::meta
== aLocal
&&
1034 (aElement
->HasAttr(kNameSpaceID_None
, nsGkAtoms::charset
) ||
1035 aElement
->HasAttr(kNameSpaceID_None
, nsGkAtoms::httpEquiv
))) {
1036 // Throw away charset declarations even if they also have microdata
1037 // which they can't validly have.
1040 if (((!mFullDocument
&& nsGkAtoms::meta
== aLocal
) ||
1041 nsGkAtoms::link
== aLocal
) &&
1042 !(aElement
->HasAttr(kNameSpaceID_None
, nsGkAtoms::itemprop
) ||
1043 aElement
->HasAttr(kNameSpaceID_None
, nsGkAtoms::itemscope
))) {
1044 // emulate old behavior for non-Microdata <meta> and <link> presumably
1045 // in <head>. <meta> and <link> are whitelisted in order to avoid
1046 // corrupting Microdata when they appear in <body>. Note that
1047 // SanitizeAttributes() will remove the rel attribute from <link> and
1048 // the name attribute from <meta>.
1053 if (nsGkAtoms::style
== aLocal
&&
1054 !(aNamespace
== kNameSpaceID_XHTML
|| aNamespace
== kNameSpaceID_SVG
)) {
1059 if (nsGkAtoms::style
== aLocal
) {
1065 bool nsTreeSanitizer::SanitizeStyleDeclaration(DeclarationBlock
* aDeclaration
) {
1066 return aDeclaration
->RemovePropertyByID(eCSSProperty__moz_binding
);
1069 bool nsTreeSanitizer::SanitizeStyleSheet(const nsAString
& aOriginal
,
1070 nsAString
& aSanitized
,
1071 Document
* aDocument
,
1073 nsresult rv
= NS_OK
;
1074 aSanitized
.Truncate();
1075 // aSanitized will hold the permitted CSS text.
1076 // -moz-binding is blacklisted.
1077 bool didSanitize
= false;
1078 // Create a sheet to hold the parsed CSS
1079 RefPtr
<StyleSheet
> sheet
=
1080 new StyleSheet(mozilla::css::eAuthorSheetFeatures
, CORS_NONE
,
1081 aDocument
->GetReferrerPolicy(), SRIMetadata());
1082 sheet
->SetURIs(aDocument
->GetDocumentURI(), nullptr, aBaseURI
);
1083 sheet
->SetPrincipal(aDocument
->NodePrincipal());
1084 sheet
->ParseSheetSync(aDocument
->CSSLoader(),
1085 NS_ConvertUTF16toUTF8(aOriginal
),
1086 /* aLoadData = */ nullptr,
1087 /* aLineNumber = */ 0);
1088 NS_ENSURE_SUCCESS(rv
, true);
1089 // Mark the sheet as complete.
1090 MOZ_ASSERT(!sheet
->HasForcedUniqueInner(),
1091 "should not get a forced unique inner during parsing");
1092 sheet
->SetComplete();
1093 // Loop through all the rules found in the CSS text
1095 RefPtr
<dom::CSSRuleList
> rules
=
1096 sheet
->GetCssRules(*nsContentUtils::GetSystemPrincipal(), err
);
1097 err
.SuppressException();
1101 uint32_t ruleCount
= rules
->Length();
1102 for (uint32_t i
= 0; i
< ruleCount
; ++i
) {
1103 mozilla::css::Rule
* rule
= rules
->Item(i
);
1104 if (!rule
) continue;
1105 switch (rule
->Type()) {
1108 // Ignore these rule types.
1110 case CSSRule_Binding::NAMESPACE_RULE
:
1111 case CSSRule_Binding::FONT_FACE_RULE
: {
1112 // Append @namespace and @font-face rules verbatim.
1113 nsAutoString cssText
;
1114 rule
->GetCssText(cssText
);
1115 aSanitized
.Append(cssText
);
1118 case CSSRule_Binding::STYLE_RULE
: {
1119 // For style rules, we will just look for and remove the
1120 // -moz-binding properties.
1121 auto styleRule
= static_cast<BindingStyleRule
*>(rule
);
1122 DeclarationBlock
* styleDecl
= styleRule
->GetDeclarationBlock();
1123 MOZ_ASSERT(styleDecl
);
1124 if (SanitizeStyleDeclaration(styleDecl
)) {
1128 styleRule
->GetCssText(decl
);
1129 aSanitized
.Append(decl
);
1133 if (didSanitize
&& mLogRemovals
) {
1134 LogMessage("Removed some rules and/or properties from stylesheet.",
1140 template <size_t Len
>
1141 static bool UTF16StringStartsWith(const char16_t
* aStr
, uint32_t aLength
,
1142 const char16_t (&aNeedle
)[Len
]) {
1143 MOZ_ASSERT(aNeedle
[Len
- 1] == '\0',
1144 "needle should be a UTF-16 encoded string literal");
1146 if (aLength
< Len
- 1) {
1149 for (size_t i
= 0; i
< Len
- 1; i
++) {
1150 if (aStr
[i
] != aNeedle
[i
]) {
1157 void nsTreeSanitizer::SanitizeAttributes(mozilla::dom::Element
* aElement
,
1158 AllowedAttributes aAllowed
) {
1159 uint32_t ac
= aElement
->GetAttrCount();
1161 for (int32_t i
= ac
- 1; i
>= 0; --i
) {
1162 const nsAttrName
* attrName
= aElement
->GetAttrNameAt(i
);
1163 int32_t attrNs
= attrName
->NamespaceID();
1164 RefPtr
<nsAtom
> attrLocal
= attrName
->LocalName();
1166 if (kNameSpaceID_None
== attrNs
) {
1167 if (aAllowed
.mStyle
&& nsGkAtoms::style
== attrLocal
) {
1169 aElement
->GetAttr(attrNs
, attrLocal
, value
);
1170 Document
* document
= aElement
->OwnerDoc();
1171 RefPtr
<URLExtraData
> urlExtra(aElement
->GetURLDataForStyleAttr());
1172 RefPtr
<DeclarationBlock
> decl
= DeclarationBlock::FromCssText(
1173 value
, urlExtra
, document
->GetCompatibilityMode(),
1174 document
->CSSLoader());
1176 if (SanitizeStyleDeclaration(decl
)) {
1177 nsAutoString cleanValue
;
1178 decl
->ToString(cleanValue
);
1179 aElement
->SetAttr(kNameSpaceID_None
, nsGkAtoms::style
, cleanValue
,
1183 "Removed -moz-binding styling from element style attribute.",
1184 aElement
->OwnerDoc(), aElement
);
1190 if (aAllowed
.mDangerousSrc
&& nsGkAtoms::src
== attrLocal
) {
1193 if (IsURL(aAllowed
.mURLs
, attrLocal
)) {
1194 if (SanitizeURL(aElement
, attrNs
, attrLocal
)) {
1195 // in case the attribute removal shuffled the attribute order, start
1198 i
= ac
; // i will be decremented immediately thanks to the for loop
1201 // else fall through to see if there's another reason to drop this
1202 // attribute (in particular if the attribute is background="" on an
1205 if (!mDropNonCSSPresentation
&&
1206 (aAllowed
.mNames
== sAttributesHTML
) && // element is HTML
1207 sPresAttributesHTML
->Contains(attrLocal
)) {
1210 if (aAllowed
.mNames
->Contains(attrLocal
) &&
1211 !((attrLocal
== nsGkAtoms::rel
&&
1212 aElement
->IsHTMLElement(nsGkAtoms::link
)) ||
1213 (!mFullDocument
&& attrLocal
== nsGkAtoms::name
&&
1214 aElement
->IsHTMLElement(nsGkAtoms::meta
)))) {
1215 // name="" and rel="" are whitelisted, but treat them as blacklisted
1216 // for <meta name> (fragment case) and <link rel> (all cases) to avoid
1217 // document-wide metadata or styling overrides with non-conforming
1218 // <meta name itemprop> or
1219 // <link rel itemprop>
1222 const char16_t
* localStr
= attrLocal
->GetUTF16String();
1223 uint32_t localLen
= attrLocal
->GetLength();
1224 // Allow underscore to cater to the MCE editor library.
1225 // Allow data-* on SVG and MathML, too, as a forward-compat measure.
1226 // Allow aria-* on all for simplicity.
1227 if (UTF16StringStartsWith(localStr
, localLen
, u
"_") ||
1228 UTF16StringStartsWith(localStr
, localLen
, u
"data-") ||
1229 UTF16StringStartsWith(localStr
, localLen
, u
"aria-")) {
1233 } else if (kNameSpaceID_XML
== attrNs
) {
1234 if (nsGkAtoms::lang
== attrLocal
|| nsGkAtoms::space
== attrLocal
) {
1238 } else if (aAllowed
.mXLink
&& kNameSpaceID_XLink
== attrNs
) {
1239 if (nsGkAtoms::href
== attrLocal
) {
1240 if (SanitizeURL(aElement
, attrNs
, attrLocal
)) {
1241 // in case the attribute removal shuffled the attribute order, start
1244 i
= ac
; // i will be decremented immediately thanks to the for loop
1248 if (nsGkAtoms::type
== attrLocal
|| nsGkAtoms::title
== attrLocal
||
1249 nsGkAtoms::show
== attrLocal
|| nsGkAtoms::actuate
== attrLocal
) {
1254 aElement
->UnsetAttr(kNameSpaceID_None
, attrLocal
, false);
1256 LogMessage("Removed unsafe attribute.", aElement
->OwnerDoc(), aElement
,
1259 // in case the attribute removal shuffled the attribute order, start the
1262 i
= ac
; // i will be decremented immediately thanks to the for loop
1265 // If we've got HTML audio or video, add the controls attribute, because
1266 // otherwise the content is unplayable with scripts removed.
1267 if (aElement
->IsAnyOfHTMLElements(nsGkAtoms::video
, nsGkAtoms::audio
)) {
1268 aElement
->SetAttr(kNameSpaceID_None
, nsGkAtoms::controls
, EmptyString(),
1273 bool nsTreeSanitizer::SanitizeURL(mozilla::dom::Element
* aElement
,
1274 int32_t aNamespace
, nsAtom
* aLocalName
) {
1276 aElement
->GetAttr(aNamespace
, aLocalName
, value
);
1278 // Get value and remove mandatory quotes
1279 static const char* kWhitespace
= "\n\r\t\b";
1280 const nsAString
& v
= nsContentUtils::TrimCharsInSet(kWhitespace
, value
);
1281 // Fragment-only url cannot be harmful.
1282 if (!v
.IsEmpty() && v
.First() == u
'#') {
1286 nsIScriptSecurityManager
* secMan
= nsContentUtils::GetSecurityManager();
1287 uint32_t flags
= nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL
;
1289 nsCOMPtr
<nsIURI
> baseURI
= aElement
->GetBaseURI();
1290 nsCOMPtr
<nsIURI
> attrURI
;
1291 nsresult rv
= NS_NewURI(getter_AddRefs(attrURI
), v
, nullptr, baseURI
);
1292 if (NS_SUCCEEDED(rv
)) {
1293 if (mCidEmbedsOnly
&& kNameSpaceID_None
== aNamespace
) {
1294 if (nsGkAtoms::src
== aLocalName
|| nsGkAtoms::background
== aLocalName
) {
1295 // comm-central uses a hack that makes nsIURIs created with cid: specs
1296 // actually have an about:blank spec. Therefore, nsIURI facilities are
1297 // useless for cid: when comm-central code is participating.
1298 if (!(v
.Length() > 4 && (v
[0] == 'c' || v
[0] == 'C') &&
1299 (v
[1] == 'i' || v
[1] == 'I') && (v
[2] == 'd' || v
[2] == 'D') &&
1301 rv
= NS_ERROR_FAILURE
;
1303 } else if (nsGkAtoms::cdgroup_
== aLocalName
||
1304 nsGkAtoms::altimg_
== aLocalName
||
1305 nsGkAtoms::definitionURL_
== aLocalName
) {
1306 // Gecko doesn't fetch these now and shouldn't in the future, but
1307 // in case someone goofs with these in the future, let's drop them.
1308 rv
= NS_ERROR_FAILURE
;
1310 rv
= secMan
->CheckLoadURIWithPrincipal(sNullPrincipal
, attrURI
, flags
);
1313 rv
= secMan
->CheckLoadURIWithPrincipal(sNullPrincipal
, attrURI
, flags
);
1316 if (NS_FAILED(rv
)) {
1317 aElement
->UnsetAttr(aNamespace
, aLocalName
, false);
1319 LogMessage("Removed unsafe URI from element attribute.",
1320 aElement
->OwnerDoc(), aElement
, aLocalName
);
1327 void nsTreeSanitizer::Sanitize(DocumentFragment
* aFragment
) {
1328 // If you want to relax these preconditions, be sure to check the code in
1329 // here that notifies / does not notify or that fires mutation events if
1331 MOZ_ASSERT(!aFragment
->IsInUncomposedDoc(), "The fragment is in doc?");
1333 mFullDocument
= false;
1334 SanitizeChildren(aFragment
);
1337 void nsTreeSanitizer::Sanitize(Document
* aDocument
) {
1338 // If you want to relax these preconditions, be sure to check the code in
1339 // here that notifies / does not notify or that fires mutation events if
1342 MOZ_ASSERT(!aDocument
->GetContainer(), "The document is in a shell.");
1343 RefPtr
<mozilla::dom::Element
> root
= aDocument
->GetRootElement();
1344 MOZ_ASSERT(root
->IsHTMLElement(nsGkAtoms::html
), "Not HTML root.");
1347 mFullDocument
= true;
1348 SanitizeChildren(aDocument
);
1351 void nsTreeSanitizer::SanitizeChildren(nsINode
* aRoot
) {
1352 nsIContent
* node
= aRoot
->GetFirstChild();
1354 if (node
->IsElement()) {
1355 mozilla::dom::Element
* elt
= node
->AsElement();
1356 mozilla::dom::NodeInfo
* nodeInfo
= node
->NodeInfo();
1357 nsAtom
* localName
= nodeInfo
->NameAtom();
1358 int32_t ns
= nodeInfo
->NamespaceID();
1360 if (MustPrune(ns
, localName
, elt
)) {
1362 LogMessage("Removing unsafe node.", elt
->OwnerDoc(), elt
);
1364 RemoveAllAttributes(elt
);
1365 nsIContent
* descendant
= node
;
1366 while ((descendant
= descendant
->GetNextNode(node
))) {
1367 if (descendant
->IsElement()) {
1368 RemoveAllAttributes(descendant
->AsElement());
1371 nsIContent
* next
= node
->GetNextNonChildNode(aRoot
);
1372 node
->RemoveFromParent();
1376 if (nsGkAtoms::style
== localName
) {
1377 // If styles aren't allowed, style elements got pruned above. Even
1378 // if styles are allowed, non-HTML, non-SVG style elements got pruned
1380 NS_ASSERTION(ns
== kNameSpaceID_XHTML
|| ns
== kNameSpaceID_SVG
,
1381 "Should have only HTML or SVG here!");
1382 nsAutoString styleText
;
1383 nsContentUtils::GetNodeTextContent(node
, false, styleText
);
1385 nsAutoString sanitizedStyle
;
1386 nsCOMPtr
<nsIURI
> baseURI
= node
->GetBaseURI();
1387 if (SanitizeStyleSheet(styleText
, sanitizedStyle
, aRoot
->OwnerDoc(),
1389 nsContentUtils::SetNodeTextContent(node
, sanitizedStyle
, true);
1391 // If the node had non-text child nodes, this operation zaps those.
1392 // XXXgijs: if we're logging, we should theoretically report about
1393 // this, but this way of removing those items doesn't allow for that
1394 // to happen. Seems less likely to be a problem for actual chrome
1395 // consumers though.
1396 nsContentUtils::SetNodeTextContent(node
, styleText
, true);
1398 AllowedAttributes allowed
;
1399 allowed
.mStyle
= mAllowStyles
;
1400 if (ns
== kNameSpaceID_XHTML
) {
1401 allowed
.mNames
= sAttributesHTML
;
1402 allowed
.mURLs
= kURLAttributesHTML
;
1403 SanitizeAttributes(elt
, allowed
);
1405 allowed
.mNames
= sAttributesSVG
;
1406 allowed
.mURLs
= kURLAttributesSVG
;
1407 allowed
.mXLink
= true;
1408 SanitizeAttributes(elt
, allowed
);
1410 node
= node
->GetNextNonChildNode(aRoot
);
1413 if (MustFlatten(ns
, localName
)) {
1415 LogMessage("Flattening unsafe node (descendants are preserved).",
1416 elt
->OwnerDoc(), elt
);
1418 RemoveAllAttributes(elt
);
1419 nsCOMPtr
<nsIContent
> next
= node
->GetNextNode(aRoot
);
1420 nsCOMPtr
<nsIContent
> parent
= node
->GetParent();
1421 nsCOMPtr
<nsIContent
> child
; // Must keep the child alive during move
1423 while ((child
= node
->GetFirstChild())) {
1424 nsCOMPtr
<nsINode
> refNode
= node
;
1425 parent
->InsertBefore(*child
, refNode
, rv
);
1430 node
->RemoveFromParent();
1434 NS_ASSERTION(ns
== kNameSpaceID_XHTML
|| ns
== kNameSpaceID_SVG
||
1435 ns
== kNameSpaceID_MathML
,
1436 "Should have only HTML, MathML or SVG here!");
1437 AllowedAttributes allowed
;
1438 if (ns
== kNameSpaceID_XHTML
) {
1439 allowed
.mNames
= sAttributesHTML
;
1440 allowed
.mURLs
= kURLAttributesHTML
;
1441 allowed
.mStyle
= mAllowStyles
;
1442 allowed
.mDangerousSrc
= nsGkAtoms::img
== localName
&& !mCidEmbedsOnly
;
1443 SanitizeAttributes(elt
, allowed
);
1444 } else if (ns
== kNameSpaceID_SVG
) {
1445 allowed
.mNames
= sAttributesSVG
;
1446 allowed
.mURLs
= kURLAttributesSVG
;
1447 allowed
.mXLink
= true;
1448 allowed
.mStyle
= mAllowStyles
;
1449 SanitizeAttributes(elt
, allowed
);
1451 allowed
.mNames
= sAttributesMathML
;
1452 allowed
.mURLs
= kURLAttributesMathML
;
1453 allowed
.mXLink
= true;
1454 SanitizeAttributes(elt
, allowed
);
1456 node
= node
->GetNextNode(aRoot
);
1459 NS_ASSERTION(!node
->GetFirstChild(), "How come non-element node had kids?");
1460 nsIContent
* next
= node
->GetNextNonChildNode(aRoot
);
1461 if (!mAllowComments
&& node
->IsComment()) {
1462 node
->RemoveFromParent();
1468 void nsTreeSanitizer::RemoveAllAttributes(Element
* aElement
) {
1469 const nsAttrName
* attrName
;
1470 while ((attrName
= aElement
->GetAttrNameAt(0))) {
1471 int32_t attrNs
= attrName
->NamespaceID();
1472 RefPtr
<nsAtom
> attrLocal
= attrName
->LocalName();
1473 aElement
->UnsetAttr(attrNs
, attrLocal
, false);
1477 void nsTreeSanitizer::LogMessage(const char* aMessage
, Document
* aDoc
,
1478 Element
* aElement
, nsAtom
* aAttr
) {
1481 msg
.Assign(NS_ConvertASCIItoUTF16(aMessage
));
1483 msg
.Append(NS_LITERAL_STRING(" Element: ") + aElement
->LocalName() +
1484 NS_LITERAL_STRING("."));
1487 msg
.Append(NS_LITERAL_STRING(" Attribute: ") +
1488 nsDependentAtomString(aAttr
) + NS_LITERAL_STRING("."));
1491 nsContentUtils::ReportToConsoleNonLocalized(
1492 msg
, nsIScriptError::warningFlag
, NS_LITERAL_CSTRING("DOM"), aDoc
);
1496 void nsTreeSanitizer::InitializeStatics() {
1497 MOZ_ASSERT(!sElementsHTML
, "Initializing a second time.");
1499 sElementsHTML
= new AtomsTable(ArrayLength(kElementsHTML
));
1500 for (uint32_t i
= 0; kElementsHTML
[i
]; i
++) {
1501 sElementsHTML
->PutEntry(kElementsHTML
[i
]);
1504 sAttributesHTML
= new AtomsTable(ArrayLength(kAttributesHTML
));
1505 for (uint32_t i
= 0; kAttributesHTML
[i
]; i
++) {
1506 sAttributesHTML
->PutEntry(kAttributesHTML
[i
]);
1509 sPresAttributesHTML
= new AtomsTable(ArrayLength(kPresAttributesHTML
));
1510 for (uint32_t i
= 0; kPresAttributesHTML
[i
]; i
++) {
1511 sPresAttributesHTML
->PutEntry(kPresAttributesHTML
[i
]);
1514 sElementsSVG
= new AtomsTable(ArrayLength(kElementsSVG
));
1515 for (uint32_t i
= 0; kElementsSVG
[i
]; i
++) {
1516 sElementsSVG
->PutEntry(kElementsSVG
[i
]);
1519 sAttributesSVG
= new AtomsTable(ArrayLength(kAttributesSVG
));
1520 for (uint32_t i
= 0; kAttributesSVG
[i
]; i
++) {
1521 sAttributesSVG
->PutEntry(kAttributesSVG
[i
]);
1524 sElementsMathML
= new AtomsTable(ArrayLength(kElementsMathML
));
1525 for (uint32_t i
= 0; kElementsMathML
[i
]; i
++) {
1526 sElementsMathML
->PutEntry(kElementsMathML
[i
]);
1529 sAttributesMathML
= new AtomsTable(ArrayLength(kAttributesMathML
));
1530 for (uint32_t i
= 0; kAttributesMathML
[i
]; i
++) {
1531 sAttributesMathML
->PutEntry(kAttributesMathML
[i
]);
1534 nsCOMPtr
<nsIPrincipal
> principal
=
1535 NullPrincipal::CreateWithoutOriginAttributes();
1536 principal
.forget(&sNullPrincipal
);
1539 void nsTreeSanitizer::ReleaseStatics() {
1540 delete sElementsHTML
;
1541 sElementsHTML
= nullptr;
1543 delete sAttributesHTML
;
1544 sAttributesHTML
= nullptr;
1546 delete sPresAttributesHTML
;
1547 sPresAttributesHTML
= nullptr;
1549 delete sElementsSVG
;
1550 sElementsSVG
= nullptr;
1552 delete sAttributesSVG
;
1553 sAttributesSVG
= nullptr;
1555 delete sElementsMathML
;
1556 sElementsMathML
= nullptr;
1558 delete sAttributesMathML
;
1559 sAttributesMathML
= nullptr;
1561 NS_IF_RELEASE(sNullPrincipal
);