Bug 1550519 - Show a translucent parent highlight when a subgrid is highlighted....
[gecko.git] / dom / base / nsTreeSanitizer.cpp
blobcc2897f315046ccd815e568dcf04c8460262bae3
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[] = {
37 // clang-format off
38 nsGkAtoms::a,
39 nsGkAtoms::abbr,
40 nsGkAtoms::acronym,
41 nsGkAtoms::address,
42 nsGkAtoms::area,
43 nsGkAtoms::article,
44 nsGkAtoms::aside,
45 nsGkAtoms::audio,
46 nsGkAtoms::b,
47 nsGkAtoms::bdi,
48 nsGkAtoms::bdo,
49 nsGkAtoms::big,
50 nsGkAtoms::blockquote,
51 // body checked specially
52 nsGkAtoms::br,
53 nsGkAtoms::button,
54 nsGkAtoms::canvas,
55 nsGkAtoms::caption,
56 nsGkAtoms::center,
57 nsGkAtoms::cite,
58 nsGkAtoms::code,
59 nsGkAtoms::col,
60 nsGkAtoms::colgroup,
61 nsGkAtoms::datalist,
62 nsGkAtoms::dd,
63 nsGkAtoms::del,
64 nsGkAtoms::details,
65 nsGkAtoms::dfn,
66 nsGkAtoms::dir,
67 nsGkAtoms::div,
68 nsGkAtoms::dl,
69 nsGkAtoms::dt,
70 nsGkAtoms::em,
71 nsGkAtoms::fieldset,
72 nsGkAtoms::figcaption,
73 nsGkAtoms::figure,
74 nsGkAtoms::font,
75 nsGkAtoms::footer,
76 nsGkAtoms::form,
77 nsGkAtoms::h1,
78 nsGkAtoms::h2,
79 nsGkAtoms::h3,
80 nsGkAtoms::h4,
81 nsGkAtoms::h5,
82 nsGkAtoms::h6,
83 // head checked specially
84 nsGkAtoms::header,
85 nsGkAtoms::hgroup,
86 nsGkAtoms::hr,
87 // html checked specially
88 nsGkAtoms::i,
89 nsGkAtoms::img,
90 nsGkAtoms::input,
91 nsGkAtoms::ins,
92 nsGkAtoms::kbd,
93 nsGkAtoms::label,
94 nsGkAtoms::legend,
95 nsGkAtoms::li,
96 nsGkAtoms::link,
97 nsGkAtoms::listing,
98 nsGkAtoms::map,
99 nsGkAtoms::mark,
100 nsGkAtoms::menu,
101 nsGkAtoms::meta,
102 nsGkAtoms::meter,
103 nsGkAtoms::nav,
104 nsGkAtoms::nobr,
105 nsGkAtoms::noscript,
106 nsGkAtoms::ol,
107 nsGkAtoms::optgroup,
108 nsGkAtoms::option,
109 nsGkAtoms::output,
110 nsGkAtoms::p,
111 nsGkAtoms::pre,
112 nsGkAtoms::progress,
113 nsGkAtoms::q,
114 nsGkAtoms::rb,
115 nsGkAtoms::rp,
116 nsGkAtoms::rt,
117 nsGkAtoms::rtc,
118 nsGkAtoms::ruby,
119 nsGkAtoms::s,
120 nsGkAtoms::samp,
121 nsGkAtoms::section,
122 nsGkAtoms::select,
123 nsGkAtoms::small,
124 nsGkAtoms::source,
125 nsGkAtoms::span,
126 nsGkAtoms::strike,
127 nsGkAtoms::strong,
128 nsGkAtoms::sub,
129 nsGkAtoms::summary,
130 nsGkAtoms::sup,
131 // style checked specially
132 nsGkAtoms::table,
133 nsGkAtoms::tbody,
134 nsGkAtoms::td,
135 nsGkAtoms::textarea,
136 nsGkAtoms::tfoot,
137 nsGkAtoms::th,
138 nsGkAtoms::thead,
139 nsGkAtoms::time,
140 // title checked specially
141 nsGkAtoms::tr,
142 nsGkAtoms::track,
143 nsGkAtoms::tt,
144 nsGkAtoms::u,
145 nsGkAtoms::ul,
146 nsGkAtoms::var,
147 nsGkAtoms::video,
148 nsGkAtoms::wbr,
149 nullptr
150 // clang-format on
153 const nsStaticAtom* const kAttributesHTML[] = {
154 // clang-format off
155 nsGkAtoms::abbr,
156 nsGkAtoms::accept,
157 nsGkAtoms::acceptcharset,
158 nsGkAtoms::accesskey,
159 nsGkAtoms::action,
160 nsGkAtoms::alt,
161 nsGkAtoms::as,
162 nsGkAtoms::autocomplete,
163 nsGkAtoms::autofocus,
164 nsGkAtoms::autoplay,
165 nsGkAtoms::axis,
166 nsGkAtoms::_char,
167 nsGkAtoms::charoff,
168 nsGkAtoms::charset,
169 nsGkAtoms::checked,
170 nsGkAtoms::cite,
171 nsGkAtoms::_class,
172 nsGkAtoms::cols,
173 nsGkAtoms::colspan,
174 nsGkAtoms::content,
175 nsGkAtoms::contenteditable,
176 nsGkAtoms::contextmenu,
177 nsGkAtoms::controls,
178 nsGkAtoms::coords,
179 nsGkAtoms::crossorigin,
180 nsGkAtoms::datetime,
181 nsGkAtoms::dir,
182 nsGkAtoms::disabled,
183 nsGkAtoms::draggable,
184 nsGkAtoms::enctype,
185 nsGkAtoms::face,
186 nsGkAtoms::_for,
187 nsGkAtoms::frame,
188 nsGkAtoms::headers,
189 nsGkAtoms::height,
190 nsGkAtoms::hidden,
191 nsGkAtoms::high,
192 nsGkAtoms::href,
193 nsGkAtoms::hreflang,
194 nsGkAtoms::icon,
195 nsGkAtoms::id,
196 nsGkAtoms::integrity,
197 nsGkAtoms::ismap,
198 nsGkAtoms::itemid,
199 nsGkAtoms::itemprop,
200 nsGkAtoms::itemref,
201 nsGkAtoms::itemscope,
202 nsGkAtoms::itemtype,
203 nsGkAtoms::kind,
204 nsGkAtoms::label,
205 nsGkAtoms::lang,
206 nsGkAtoms::list_,
207 nsGkAtoms::longdesc,
208 nsGkAtoms::loop,
209 nsGkAtoms::low,
210 nsGkAtoms::max,
211 nsGkAtoms::maxlength,
212 nsGkAtoms::media,
213 nsGkAtoms::method,
214 nsGkAtoms::min,
215 nsGkAtoms::minlength,
216 nsGkAtoms::multiple,
217 nsGkAtoms::muted,
218 nsGkAtoms::name,
219 nsGkAtoms::nohref,
220 nsGkAtoms::novalidate,
221 nsGkAtoms::nowrap,
222 nsGkAtoms::open,
223 nsGkAtoms::optimum,
224 nsGkAtoms::pattern,
225 nsGkAtoms::placeholder,
226 nsGkAtoms::playbackrate,
227 nsGkAtoms::poster,
228 nsGkAtoms::preload,
229 nsGkAtoms::prompt,
230 nsGkAtoms::pubdate,
231 nsGkAtoms::radiogroup,
232 nsGkAtoms::readonly,
233 nsGkAtoms::rel,
234 nsGkAtoms::required,
235 nsGkAtoms::rev,
236 nsGkAtoms::reversed,
237 nsGkAtoms::role,
238 nsGkAtoms::rows,
239 nsGkAtoms::rowspan,
240 nsGkAtoms::rules,
241 nsGkAtoms::scoped,
242 nsGkAtoms::scope,
243 nsGkAtoms::selected,
244 nsGkAtoms::shape,
245 nsGkAtoms::span,
246 nsGkAtoms::spellcheck,
247 nsGkAtoms::src,
248 nsGkAtoms::srclang,
249 nsGkAtoms::start,
250 nsGkAtoms::summary,
251 nsGkAtoms::tabindex,
252 nsGkAtoms::target,
253 nsGkAtoms::title,
254 nsGkAtoms::type,
255 nsGkAtoms::usemap,
256 nsGkAtoms::value,
257 nsGkAtoms::width,
258 nsGkAtoms::wrap,
259 nullptr
260 // clang-format on
263 const nsStaticAtom* const kPresAttributesHTML[] = {
264 // clang-format off
265 nsGkAtoms::align,
266 nsGkAtoms::background,
267 nsGkAtoms::bgcolor,
268 nsGkAtoms::border,
269 nsGkAtoms::cellpadding,
270 nsGkAtoms::cellspacing,
271 nsGkAtoms::color,
272 nsGkAtoms::compact,
273 nsGkAtoms::clear,
274 nsGkAtoms::hspace,
275 nsGkAtoms::noshade,
276 nsGkAtoms::pointSize,
277 nsGkAtoms::size,
278 nsGkAtoms::valign,
279 nsGkAtoms::vspace,
280 nullptr
281 // clang-format on
284 const nsStaticAtom* const kURLAttributesHTML[] = {
285 // clang-format off
286 nsGkAtoms::action,
287 nsGkAtoms::href,
288 nsGkAtoms::src,
289 nsGkAtoms::longdesc,
290 nsGkAtoms::cite,
291 nsGkAtoms::background,
292 nullptr
293 // clang-format on
296 const nsStaticAtom* const kElementsSVG[] = {
297 nsGkAtoms::a, // a
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
307 nsGkAtoms::ex, // ex
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
343 nsGkAtoms::g, // g
344 // glyph
345 nsGkAtoms::glyphRef, // glyphRef
346 // hkern
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
372 // vkern
373 nullptr};
375 const nsStaticAtom* const kAttributesSVG[] = {
376 // accent-height
377 nsGkAtoms::accumulate, // accumulate
378 nsGkAtoms::additive, // additive
379 nsGkAtoms::alignment_baseline, // alignment-baseline
380 // alphabetic
381 nsGkAtoms::amplitude, // amplitude
382 // arabic-form
383 // ascent
384 nsGkAtoms::attributeName, // attributeName
385 nsGkAtoms::attributeType, // attributeType
386 nsGkAtoms::azimuth, // azimuth
387 nsGkAtoms::baseFrequency, // baseFrequency
388 nsGkAtoms::baseline_shift, // baseline-shift
389 // baseProfile
390 // bbox
391 nsGkAtoms::begin, // begin
392 nsGkAtoms::bias, // bias
393 nsGkAtoms::by, // by
394 nsGkAtoms::calcMode, // calcMode
395 // cap-height
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
404 nsGkAtoms::cx, // cx
405 nsGkAtoms::cy, // cy
406 nsGkAtoms::d, // d
407 // descent
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
414 nsGkAtoms::dx, // dx
415 nsGkAtoms::dy, // dy
416 nsGkAtoms::edgeMode, // edgeMode
417 nsGkAtoms::elevation, // elevation
418 // enable-background
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
427 // XXX focusable
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
438 nsGkAtoms::fx, // fx
439 nsGkAtoms::fy, // fy
440 // g1
441 // g2
442 // glyph-name
443 // glyphRef
444 // glyph-orientation-horizontal
445 // glyph-orientation-vertical
446 nsGkAtoms::gradientTransform, // gradientTransform
447 nsGkAtoms::gradientUnits, // gradientUnits
448 nsGkAtoms::height, // height
449 // horiz-adv-x
450 // horiz-origin-x
451 // horiz-origin-y
452 nsGkAtoms::id, // id
453 // ideographic
454 nsGkAtoms::image_rendering, // image-rendering
455 nsGkAtoms::in, // in
456 nsGkAtoms::in2, // in2
457 nsGkAtoms::intercept, // intercept
458 // k
459 nsGkAtoms::k1, // k1
460 nsGkAtoms::k2, // k2
461 nsGkAtoms::k3, // k3
462 nsGkAtoms::k4, // k4
463 // kerning
464 nsGkAtoms::kernelMatrix, // kernelMatrix
465 nsGkAtoms::kernelUnitLength, // kernelUnitLength
466 nsGkAtoms::keyPoints, // keyPoints
467 nsGkAtoms::keySplines, // keySplines
468 nsGkAtoms::keyTimes, // keyTimes
469 nsGkAtoms::lang, // lang
470 // lengthAdjust
471 nsGkAtoms::letter_spacing, // letter-spacing
472 nsGkAtoms::lighting_color, // lighting-color
473 nsGkAtoms::limitingConeAngle, // limitingConeAngle
474 // local
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
485 // mathematical
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
499 // origin
500 // overline-position
501 // overline-thickness
502 nsGkAtoms::overflow, // overflow
503 // panose-1
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
517 nsGkAtoms::r, // r
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
528 nsGkAtoms::rx, // rx
529 nsGkAtoms::ry, // ry
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
540 // stemh
541 // stemv
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
564 // textLength
565 nsGkAtoms::text_rendering, // text-rendering
566 nsGkAtoms::title, // title
567 nsGkAtoms::to, // to
568 nsGkAtoms::transform, // transform
569 nsGkAtoms::type, // type
570 // u1
571 // u2
572 // underline-position
573 // underline-thickness
574 // unicode
575 nsGkAtoms::unicode_bidi, // unicode-bidi
576 // unicode-range
577 // units-per-em
578 // v-alphabetic
579 // v-hanging
580 // v-ideographic
581 // v-mathematical
582 nsGkAtoms::values, // values
583 nsGkAtoms::vector_effect, // vector-effect
584 // vert-adv-y
585 // vert-origin-x
586 // vert-origin-y
587 nsGkAtoms::viewBox, // viewBox
588 nsGkAtoms::viewTarget, // viewTarget
589 nsGkAtoms::visibility, // visibility
590 nsGkAtoms::width, // width
591 // widths
592 nsGkAtoms::word_spacing, // word-spacing
593 nsGkAtoms::writing_mode, // writing-mode
594 nsGkAtoms::x, // x
595 // x-height
596 nsGkAtoms::x1, // x1
597 nsGkAtoms::x2, // x2
598 nsGkAtoms::xChannelSelector, // xChannelSelector
599 nsGkAtoms::y, // y
600 nsGkAtoms::y1, // y1
601 nsGkAtoms::y2, // y2
602 nsGkAtoms::yChannelSelector, // yChannelSelector
603 nsGkAtoms::z, // z
604 nsGkAtoms::zoomAndPan, // zoomAndPan
605 nullptr};
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
660 nsGkAtoms::el, // el
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
683 nsGkAtoms::in, // in
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
805 nullptr};
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
856 nsGkAtoms::id, // id
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
922 nullptr};
924 const nsStaticAtom* const kURLAttributesMathML[] = {
925 // clang-format off
926 nsGkAtoms::href,
927 nsGkAtoms::src,
928 nsGkAtoms::cdgroup_,
929 nsGkAtoms::altimg_,
930 nsGkAtoms::definitionURL_,
931 nullptr
932 // clang-format on
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.
961 InitializeStatics();
965 bool nsTreeSanitizer::MustFlatten(int32_t aNamespace, nsAtom* aLocal) {
966 if (aNamespace == kNameSpaceID_XHTML) {
967 if (mDropNonCSSPresentation &&
968 (nsGkAtoms::font == aLocal || nsGkAtoms::center == aLocal)) {
969 return true;
971 if (mDropForms &&
972 (nsGkAtoms::form == aLocal || nsGkAtoms::input == aLocal ||
973 nsGkAtoms::keygen == aLocal || nsGkAtoms::option == aLocal ||
974 nsGkAtoms::optgroup == aLocal)) {
975 return true;
977 if (mFullDocument &&
978 (nsGkAtoms::title == aLocal || nsGkAtoms::html == aLocal ||
979 nsGkAtoms::head == aLocal || nsGkAtoms::body == aLocal)) {
980 return false;
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.
988 return true;
990 return !sElementsSVG->Contains(aLocal);
992 if (aNamespace == kNameSpaceID_MathML) {
993 return !sElementsMathML->Contains(aLocal);
995 return true;
998 bool nsTreeSanitizer::IsURL(const nsStaticAtom* const* aURLs,
999 nsAtom* aLocalName) {
1000 const nsStaticAtom* atom;
1001 while ((atom = *aURLs)) {
1002 if (atom == aLocalName) {
1003 return true;
1005 ++aURLs;
1007 return false;
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) {
1016 return true;
1018 if (aNamespace == kNameSpaceID_XHTML) {
1019 if (nsGkAtoms::title == aLocal && !mFullDocument) {
1020 // emulate the quirks of the old parser
1021 return true;
1023 if (mDropForms &&
1024 (nsGkAtoms::select == aLocal || nsGkAtoms::button == aLocal ||
1025 nsGkAtoms::datalist == aLocal)) {
1026 return true;
1028 if (mDropMedia &&
1029 (nsGkAtoms::img == aLocal || nsGkAtoms::video == aLocal ||
1030 nsGkAtoms::audio == aLocal || nsGkAtoms::source == aLocal)) {
1031 return true;
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.
1038 return true;
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>.
1049 return true;
1052 if (mAllowStyles) {
1053 if (nsGkAtoms::style == aLocal &&
1054 !(aNamespace == kNameSpaceID_XHTML || aNamespace == kNameSpaceID_SVG)) {
1055 return true;
1057 return false;
1059 if (nsGkAtoms::style == aLocal) {
1060 return true;
1062 return false;
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,
1072 nsIURI* aBaseURI) {
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
1094 ErrorResult err;
1095 RefPtr<dom::CSSRuleList> rules =
1096 sheet->GetCssRules(*nsContentUtils::GetSystemPrincipal(), err);
1097 err.SuppressException();
1098 if (!rules) {
1099 return true;
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()) {
1106 default:
1107 didSanitize = true;
1108 // Ignore these rule types.
1109 break;
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);
1116 break;
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)) {
1125 didSanitize = true;
1127 nsAutoString decl;
1128 styleRule->GetCssText(decl);
1129 aSanitized.Append(decl);
1133 if (didSanitize && mLogRemovals) {
1134 LogMessage("Removed some rules and/or properties from stylesheet.",
1135 aDocument);
1137 return didSanitize;
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) {
1147 return false;
1149 for (size_t i = 0; i < Len - 1; i++) {
1150 if (aStr[i] != aNeedle[i]) {
1151 return false;
1154 return true;
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) {
1168 nsAutoString value;
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());
1175 if (decl) {
1176 if (SanitizeStyleDeclaration(decl)) {
1177 nsAutoString cleanValue;
1178 decl->ToString(cleanValue);
1179 aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::style, cleanValue,
1180 false);
1181 if (mLogRemovals) {
1182 LogMessage(
1183 "Removed -moz-binding styling from element style attribute.",
1184 aElement->OwnerDoc(), aElement);
1188 continue;
1190 if (aAllowed.mDangerousSrc && nsGkAtoms::src == attrLocal) {
1191 continue;
1193 if (IsURL(aAllowed.mURLs, attrLocal)) {
1194 if (SanitizeURL(aElement, attrNs, attrLocal)) {
1195 // in case the attribute removal shuffled the attribute order, start
1196 // the loop again.
1197 --ac;
1198 i = ac; // i will be decremented immediately thanks to the for loop
1199 continue;
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
1203 // HTML element)
1205 if (!mDropNonCSSPresentation &&
1206 (aAllowed.mNames == sAttributesHTML) && // element is HTML
1207 sPresAttributesHTML->Contains(attrLocal)) {
1208 continue;
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>
1220 continue;
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-")) {
1230 continue;
1232 // else not allowed
1233 } else if (kNameSpaceID_XML == attrNs) {
1234 if (nsGkAtoms::lang == attrLocal || nsGkAtoms::space == attrLocal) {
1235 continue;
1237 // else not allowed
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
1242 // the loop again.
1243 --ac;
1244 i = ac; // i will be decremented immediately thanks to the for loop
1246 continue;
1248 if (nsGkAtoms::type == attrLocal || nsGkAtoms::title == attrLocal ||
1249 nsGkAtoms::show == attrLocal || nsGkAtoms::actuate == attrLocal) {
1250 continue;
1252 // else not allowed
1254 aElement->UnsetAttr(kNameSpaceID_None, attrLocal, false);
1255 if (mLogRemovals) {
1256 LogMessage("Removed unsafe attribute.", aElement->OwnerDoc(), aElement,
1257 attrLocal);
1259 // in case the attribute removal shuffled the attribute order, start the
1260 // loop again.
1261 --ac;
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(),
1269 false);
1273 bool nsTreeSanitizer::SanitizeURL(mozilla::dom::Element* aElement,
1274 int32_t aNamespace, nsAtom* aLocalName) {
1275 nsAutoString value;
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'#') {
1283 return false;
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') &&
1300 v[3] == ':')) {
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;
1309 } else {
1310 rv = secMan->CheckLoadURIWithPrincipal(sNullPrincipal, attrURI, flags);
1312 } else {
1313 rv = secMan->CheckLoadURIWithPrincipal(sNullPrincipal, attrURI, flags);
1316 if (NS_FAILED(rv)) {
1317 aElement->UnsetAttr(aNamespace, aLocalName, false);
1318 if (mLogRemovals) {
1319 LogMessage("Removed unsafe URI from element attribute.",
1320 aElement->OwnerDoc(), aElement, aLocalName);
1322 return true;
1324 return false;
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
1330 // in tree.
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
1340 // in tree.
1341 #ifdef DEBUG
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.");
1345 #endif
1347 mFullDocument = true;
1348 SanitizeChildren(aDocument);
1351 void nsTreeSanitizer::SanitizeChildren(nsINode* aRoot) {
1352 nsIContent* node = aRoot->GetFirstChild();
1353 while (node) {
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)) {
1361 if (mLogRemovals) {
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();
1373 node = next;
1374 continue;
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
1379 // above.
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(),
1388 baseURI)) {
1389 nsContentUtils::SetNodeTextContent(node, sanitizedStyle, true);
1390 } else {
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);
1404 } else {
1405 allowed.mNames = sAttributesSVG;
1406 allowed.mURLs = kURLAttributesSVG;
1407 allowed.mXLink = true;
1408 SanitizeAttributes(elt, allowed);
1410 node = node->GetNextNonChildNode(aRoot);
1411 continue;
1413 if (MustFlatten(ns, localName)) {
1414 if (mLogRemovals) {
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
1422 ErrorResult rv;
1423 while ((child = node->GetFirstChild())) {
1424 nsCOMPtr<nsINode> refNode = node;
1425 parent->InsertBefore(*child, refNode, rv);
1426 if (rv.Failed()) {
1427 break;
1430 node->RemoveFromParent();
1431 node = next;
1432 continue;
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);
1450 } else {
1451 allowed.mNames = sAttributesMathML;
1452 allowed.mURLs = kURLAttributesMathML;
1453 allowed.mXLink = true;
1454 SanitizeAttributes(elt, allowed);
1456 node = node->GetNextNode(aRoot);
1457 continue;
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();
1464 node = next;
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) {
1479 if (mLogRemovals) {
1480 nsAutoString msg;
1481 msg.Assign(NS_ConvertASCIItoUTF16(aMessage));
1482 if (aElement) {
1483 msg.Append(NS_LITERAL_STRING(" Element: ") + aElement->LocalName() +
1484 NS_LITERAL_STRING("."));
1486 if (aAttr) {
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);