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/. */
6 
7 #include "nsTreeSanitizer.h"
8 
9 #include "mozilla/Algorithm.h"
10 #include "mozilla/ArrayUtils.h"
11 #include "mozilla/BindingStyleRule.h"
12 #include "mozilla/DeclarationBlock.h"
13 #include "mozilla/StyleSheetInlines.h"
14 #include "mozilla/UniquePtr.h"
15 #include "mozilla/css/Rule.h"
16 #include "mozilla/dom/SanitizerBinding.h"
17 #include "mozilla/dom/CSSRuleList.h"
18 #include "mozilla/dom/DocumentFragment.h"
19 #include "mozilla/dom/HTMLTemplateElement.h"
20 #include "mozilla/dom/SRIMetadata.h"
21 #include "mozilla/NullPrincipal.h"
22 #include "nsAtom.h"
23 #include "nsCSSPropertyID.h"
24 #include "nsHashtablesFwd.h"
25 #include "nsString.h"
26 #include "nsTHashtable.h"
27 #include "nsUnicharInputStream.h"
28 #include "nsAttrName.h"
29 #include "nsIScriptError.h"
30 #include "nsIScriptSecurityManager.h"
31 #include "nsNetUtil.h"
32 #include "nsComponentManagerUtils.h"
33 #include "nsContentUtils.h"
34 #include "nsIParserUtils.h"
35 #include "mozilla/dom/Document.h"
36 #include "nsQueryObject.h"
37 
38 #include <iterator>
39 
40 using namespace mozilla;
41 using namespace mozilla::dom;
42 
43 //
44 // Thanks to Mark Pilgrim and Sam Ruby for the initial whitelist
45 //
46 const nsStaticAtom* const kElementsHTML[] = {
47     // clang-format off
48   nsGkAtoms::a,
49   nsGkAtoms::abbr,
50   nsGkAtoms::acronym,
51   nsGkAtoms::address,
52   nsGkAtoms::area,
53   nsGkAtoms::article,
54   nsGkAtoms::aside,
55   nsGkAtoms::audio,
56   nsGkAtoms::b,
57   nsGkAtoms::bdi,
58   nsGkAtoms::bdo,
59   nsGkAtoms::big,
60   nsGkAtoms::blockquote,
61   // body checked specially
62   nsGkAtoms::br,
63   nsGkAtoms::button,
64   nsGkAtoms::canvas,
65   nsGkAtoms::caption,
66   nsGkAtoms::center,
67   nsGkAtoms::cite,
68   nsGkAtoms::code,
69   nsGkAtoms::col,
70   nsGkAtoms::colgroup,
71   nsGkAtoms::data,
72   nsGkAtoms::datalist,
73   nsGkAtoms::dd,
74   nsGkAtoms::del,
75   nsGkAtoms::details,
76   nsGkAtoms::dfn,
77   nsGkAtoms::dialog,
78   nsGkAtoms::dir,
79   nsGkAtoms::div,
80   nsGkAtoms::dl,
81   nsGkAtoms::dt,
82   nsGkAtoms::em,
83   nsGkAtoms::fieldset,
84   nsGkAtoms::figcaption,
85   nsGkAtoms::figure,
86   nsGkAtoms::font,
87   nsGkAtoms::footer,
88   nsGkAtoms::form,
89   nsGkAtoms::h1,
90   nsGkAtoms::h2,
91   nsGkAtoms::h3,
92   nsGkAtoms::h4,
93   nsGkAtoms::h5,
94   nsGkAtoms::h6,
95   // head checked specially
96   nsGkAtoms::header,
97   nsGkAtoms::hgroup,
98   nsGkAtoms::hr,
99   // html checked specially
100   nsGkAtoms::i,
101   nsGkAtoms::img,
102   nsGkAtoms::input,
103   nsGkAtoms::ins,
104   nsGkAtoms::kbd,
105   nsGkAtoms::keygen,
106   nsGkAtoms::label,
107   nsGkAtoms::legend,
108   nsGkAtoms::li,
109   nsGkAtoms::link,
110   nsGkAtoms::listing,
111   nsGkAtoms::main,
112   nsGkAtoms::map,
113   nsGkAtoms::mark,
114   nsGkAtoms::menu,
115   nsGkAtoms::meta,
116   nsGkAtoms::meter,
117   nsGkAtoms::nav,
118   nsGkAtoms::nobr,
119   nsGkAtoms::noscript,
120   nsGkAtoms::ol,
121   nsGkAtoms::optgroup,
122   nsGkAtoms::option,
123   nsGkAtoms::output,
124   nsGkAtoms::p,
125   nsGkAtoms::picture,
126   nsGkAtoms::pre,
127   nsGkAtoms::progress,
128   nsGkAtoms::q,
129   nsGkAtoms::rb,
130   nsGkAtoms::rp,
131   nsGkAtoms::rt,
132   nsGkAtoms::rtc,
133   nsGkAtoms::ruby,
134   nsGkAtoms::s,
135   nsGkAtoms::samp,
136   nsGkAtoms::section,
137   nsGkAtoms::select,
138   nsGkAtoms::small,
139   nsGkAtoms::source,
140   nsGkAtoms::span,
141   nsGkAtoms::strike,
142   nsGkAtoms::strong,
143   nsGkAtoms::sub,
144   nsGkAtoms::summary,
145   nsGkAtoms::sup,
146   // style checked specially
147   nsGkAtoms::table,
148   nsGkAtoms::tbody,
149   nsGkAtoms::td,
150   // template checked and traversed specially
151   nsGkAtoms::textarea,
152   nsGkAtoms::tfoot,
153   nsGkAtoms::th,
154   nsGkAtoms::thead,
155   nsGkAtoms::time,
156   // title checked specially
157   nsGkAtoms::tr,
158   nsGkAtoms::track,
159   nsGkAtoms::tt,
160   nsGkAtoms::u,
161   nsGkAtoms::ul,
162   nsGkAtoms::var,
163   nsGkAtoms::video,
164   nsGkAtoms::wbr,
165   nullptr
166     // clang-format on
167 };
168 
169 const nsStaticAtom* const kAttributesHTML[] = {
170     // clang-format off
171   nsGkAtoms::abbr,
172   nsGkAtoms::accept,
173   nsGkAtoms::acceptcharset,
174   nsGkAtoms::accesskey,
175   nsGkAtoms::action,
176   nsGkAtoms::alt,
177   nsGkAtoms::as,
178   nsGkAtoms::autocomplete,
179   nsGkAtoms::autofocus,
180   nsGkAtoms::autoplay,
181   nsGkAtoms::axis,
182   nsGkAtoms::_char,
183   nsGkAtoms::charoff,
184   nsGkAtoms::charset,
185   nsGkAtoms::checked,
186   nsGkAtoms::cite,
187   nsGkAtoms::_class,
188   nsGkAtoms::cols,
189   nsGkAtoms::colspan,
190   nsGkAtoms::content,
191   nsGkAtoms::contenteditable,
192   nsGkAtoms::contextmenu,
193   nsGkAtoms::controls,
194   nsGkAtoms::coords,
195   nsGkAtoms::crossorigin,
196   nsGkAtoms::datetime,
197   nsGkAtoms::dir,
198   nsGkAtoms::disabled,
199   nsGkAtoms::draggable,
200   nsGkAtoms::enctype,
201   nsGkAtoms::face,
202   nsGkAtoms::_for,
203   nsGkAtoms::frame,
204   nsGkAtoms::headers,
205   nsGkAtoms::height,
206   nsGkAtoms::hidden,
207   nsGkAtoms::high,
208   nsGkAtoms::href,
209   nsGkAtoms::hreflang,
210   nsGkAtoms::icon,
211   nsGkAtoms::id,
212   nsGkAtoms::integrity,
213   nsGkAtoms::ismap,
214   nsGkAtoms::itemid,
215   nsGkAtoms::itemprop,
216   nsGkAtoms::itemref,
217   nsGkAtoms::itemscope,
218   nsGkAtoms::itemtype,
219   nsGkAtoms::kind,
220   nsGkAtoms::label,
221   nsGkAtoms::lang,
222   nsGkAtoms::list_,
223   nsGkAtoms::longdesc,
224   nsGkAtoms::loop,
225   nsGkAtoms::low,
226   nsGkAtoms::max,
227   nsGkAtoms::maxlength,
228   nsGkAtoms::media,
229   nsGkAtoms::method,
230   nsGkAtoms::min,
231   nsGkAtoms::minlength,
232   nsGkAtoms::multiple,
233   nsGkAtoms::muted,
234   nsGkAtoms::name,
235   nsGkAtoms::nohref,
236   nsGkAtoms::novalidate,
237   nsGkAtoms::nowrap,
238   nsGkAtoms::open,
239   nsGkAtoms::optimum,
240   nsGkAtoms::pattern,
241   nsGkAtoms::placeholder,
242   nsGkAtoms::playbackrate,
243   nsGkAtoms::poster,
244   nsGkAtoms::preload,
245   nsGkAtoms::prompt,
246   nsGkAtoms::pubdate,
247   nsGkAtoms::radiogroup,
248   nsGkAtoms::readonly,
249   nsGkAtoms::rel,
250   nsGkAtoms::required,
251   nsGkAtoms::rev,
252   nsGkAtoms::reversed,
253   nsGkAtoms::role,
254   nsGkAtoms::rows,
255   nsGkAtoms::rowspan,
256   nsGkAtoms::rules,
257   nsGkAtoms::scoped,
258   nsGkAtoms::scope,
259   nsGkAtoms::selected,
260   nsGkAtoms::shape,
261   nsGkAtoms::span,
262   nsGkAtoms::spellcheck,
263   nsGkAtoms::src,
264   nsGkAtoms::srclang,
265   nsGkAtoms::start,
266   nsGkAtoms::summary,
267   nsGkAtoms::tabindex,
268   nsGkAtoms::target,
269   nsGkAtoms::title,
270   nsGkAtoms::type,
271   nsGkAtoms::usemap,
272   nsGkAtoms::value,
273   nsGkAtoms::width,
274   nsGkAtoms::wrap,
275   nullptr
276     // clang-format on
277 };
278 
279 const nsStaticAtom* const kPresAttributesHTML[] = {
280     // clang-format off
281   nsGkAtoms::align,
282   nsGkAtoms::background,
283   nsGkAtoms::bgcolor,
284   nsGkAtoms::border,
285   nsGkAtoms::cellpadding,
286   nsGkAtoms::cellspacing,
287   nsGkAtoms::color,
288   nsGkAtoms::compact,
289   nsGkAtoms::clear,
290   nsGkAtoms::hspace,
291   nsGkAtoms::noshade,
292   nsGkAtoms::pointSize,
293   nsGkAtoms::size,
294   nsGkAtoms::valign,
295   nsGkAtoms::vspace,
296   nullptr
297     // clang-format on
298 };
299 
300 // List of HTML attributes with URLs that the
301 // browser will fetch. Should be kept in sync with
302 // https://html.spec.whatwg.org/multipage/indices.html#attributes-3
303 const nsStaticAtom* const kURLAttributesHTML[] = {
304     // clang-format off
305   nsGkAtoms::action,
306   nsGkAtoms::href,
307   nsGkAtoms::src,
308   nsGkAtoms::longdesc,
309   nsGkAtoms::cite,
310   nsGkAtoms::background,
311   nsGkAtoms::formaction,
312   nsGkAtoms::data,
313   nsGkAtoms::ping,
314   nsGkAtoms::poster,
315   nullptr
316     // clang-format on
317 };
318 
319 const nsStaticAtom* const kElementsSVG[] = {
320     nsGkAtoms::a,                    // a
321     nsGkAtoms::circle,               // circle
322     nsGkAtoms::clipPath,             // clipPath
323     nsGkAtoms::colorProfile,         // color-profile
324     nsGkAtoms::cursor,               // cursor
325     nsGkAtoms::defs,                 // defs
326     nsGkAtoms::desc,                 // desc
327     nsGkAtoms::ellipse,              // ellipse
328     nsGkAtoms::elevation,            // elevation
329     nsGkAtoms::erode,                // erode
330     nsGkAtoms::ex,                   // ex
331     nsGkAtoms::exact,                // exact
332     nsGkAtoms::exponent,             // exponent
333     nsGkAtoms::feBlend,              // feBlend
334     nsGkAtoms::feColorMatrix,        // feColorMatrix
335     nsGkAtoms::feComponentTransfer,  // feComponentTransfer
336     nsGkAtoms::feComposite,          // feComposite
337     nsGkAtoms::feConvolveMatrix,     // feConvolveMatrix
338     nsGkAtoms::feDiffuseLighting,    // feDiffuseLighting
339     nsGkAtoms::feDisplacementMap,    // feDisplacementMap
340     nsGkAtoms::feDistantLight,       // feDistantLight
341     nsGkAtoms::feDropShadow,         // feDropShadow
342     nsGkAtoms::feFlood,              // feFlood
343     nsGkAtoms::feFuncA,              // feFuncA
344     nsGkAtoms::feFuncB,              // feFuncB
345     nsGkAtoms::feFuncG,              // feFuncG
346     nsGkAtoms::feFuncR,              // feFuncR
347     nsGkAtoms::feGaussianBlur,       // feGaussianBlur
348     nsGkAtoms::feImage,              // feImage
349     nsGkAtoms::feMerge,              // feMerge
350     nsGkAtoms::feMergeNode,          // feMergeNode
351     nsGkAtoms::feMorphology,         // feMorphology
352     nsGkAtoms::feOffset,             // feOffset
353     nsGkAtoms::fePointLight,         // fePointLight
354     nsGkAtoms::feSpecularLighting,   // feSpecularLighting
355     nsGkAtoms::feSpotLight,          // feSpotLight
356     nsGkAtoms::feTile,               // feTile
357     nsGkAtoms::feTurbulence,         // feTurbulence
358     nsGkAtoms::filter,               // filter
359     nsGkAtoms::font,                 // font
360     nsGkAtoms::font_face,            // font-face
361     nsGkAtoms::font_face_format,     // font-face-format
362     nsGkAtoms::font_face_name,       // font-face-name
363     nsGkAtoms::font_face_src,        // font-face-src
364     nsGkAtoms::font_face_uri,        // font-face-uri
365     nsGkAtoms::foreignObject,        // foreignObject
366     nsGkAtoms::g,                    // g
367     // glyph
368     nsGkAtoms::glyphRef,  // glyphRef
369     // hkern
370     nsGkAtoms::image,           // image
371     nsGkAtoms::line,            // line
372     nsGkAtoms::linearGradient,  // linearGradient
373     nsGkAtoms::marker,          // marker
374     nsGkAtoms::mask,            // mask
375     nsGkAtoms::metadata,        // metadata
376     nsGkAtoms::missingGlyph,    // missingGlyph
377     nsGkAtoms::mpath,           // mpath
378     nsGkAtoms::path,            // path
379     nsGkAtoms::pattern,         // pattern
380     nsGkAtoms::polygon,         // polygon
381     nsGkAtoms::polyline,        // polyline
382     nsGkAtoms::radialGradient,  // radialGradient
383     nsGkAtoms::rect,            // rect
384     nsGkAtoms::stop,            // stop
385     nsGkAtoms::svg,             // svg
386     nsGkAtoms::svgSwitch,       // switch
387     nsGkAtoms::symbol,          // symbol
388     nsGkAtoms::text,            // text
389     nsGkAtoms::textPath,        // textPath
390     nsGkAtoms::title,           // title
391     nsGkAtoms::tref,            // tref
392     nsGkAtoms::tspan,           // tspan
393     nsGkAtoms::use,             // use
394     nsGkAtoms::view,            // view
395     // vkern
396     nullptr};
397 
398 constexpr const nsStaticAtom* const kAttributesSVG[] = {
399     // accent-height
400     nsGkAtoms::accumulate,          // accumulate
401     nsGkAtoms::additive,            // additive
402     nsGkAtoms::alignment_baseline,  // alignment-baseline
403     // alphabetic
404     nsGkAtoms::amplitude,  // amplitude
405     // arabic-form
406     // ascent
407     nsGkAtoms::attributeName,   // attributeName
408     nsGkAtoms::attributeType,   // attributeType
409     nsGkAtoms::azimuth,         // azimuth
410     nsGkAtoms::baseFrequency,   // baseFrequency
411     nsGkAtoms::baseline_shift,  // baseline-shift
412     // baseProfile
413     // bbox
414     nsGkAtoms::begin,     // begin
415     nsGkAtoms::bias,      // bias
416     nsGkAtoms::by,        // by
417     nsGkAtoms::calcMode,  // calcMode
418     // cap-height
419     nsGkAtoms::_class,                     // class
420     nsGkAtoms::clip_path,                  // clip-path
421     nsGkAtoms::clip_rule,                  // clip-rule
422     nsGkAtoms::clipPathUnits,              // clipPathUnits
423     nsGkAtoms::color,                      // color
424     nsGkAtoms::colorInterpolation,         // color-interpolation
425     nsGkAtoms::colorInterpolationFilters,  // color-interpolation-filters
426     nsGkAtoms::cursor,                     // cursor
427     nsGkAtoms::cx,                         // cx
428     nsGkAtoms::cy,                         // cy
429     nsGkAtoms::d,                          // d
430     // descent
431     nsGkAtoms::diffuseConstant,    // diffuseConstant
432     nsGkAtoms::direction,          // direction
433     nsGkAtoms::display,            // display
434     nsGkAtoms::divisor,            // divisor
435     nsGkAtoms::dominant_baseline,  // dominant-baseline
436     nsGkAtoms::dur,                // dur
437     nsGkAtoms::dx,                 // dx
438     nsGkAtoms::dy,                 // dy
439     nsGkAtoms::edgeMode,           // edgeMode
440     nsGkAtoms::elevation,          // elevation
441     // enable-background
442     nsGkAtoms::end,            // end
443     nsGkAtoms::fill,           // fill
444     nsGkAtoms::fill_opacity,   // fill-opacity
445     nsGkAtoms::fill_rule,      // fill-rule
446     nsGkAtoms::filter,         // filter
447     nsGkAtoms::filterUnits,    // filterUnits
448     nsGkAtoms::flood_color,    // flood-color
449     nsGkAtoms::flood_opacity,  // flood-opacity
450     // XXX focusable
451     nsGkAtoms::font,              // font
452     nsGkAtoms::font_family,       // font-family
453     nsGkAtoms::font_size,         // font-size
454     nsGkAtoms::font_size_adjust,  // font-size-adjust
455     nsGkAtoms::font_stretch,      // font-stretch
456     nsGkAtoms::font_style,        // font-style
457     nsGkAtoms::font_variant,      // font-variant
458     nsGkAtoms::fontWeight,        // font-weight
459     nsGkAtoms::format,            // format
460     nsGkAtoms::from,              // from
461     nsGkAtoms::fx,                // fx
462     nsGkAtoms::fy,                // fy
463     // g1
464     // g2
465     // glyph-name
466     // glyphRef
467     // glyph-orientation-horizontal
468     // glyph-orientation-vertical
469     nsGkAtoms::gradientTransform,  // gradientTransform
470     nsGkAtoms::gradientUnits,      // gradientUnits
471     nsGkAtoms::height,             // height
472     nsGkAtoms::href,
473     // horiz-adv-x
474     // horiz-origin-x
475     // horiz-origin-y
476     nsGkAtoms::id,  // id
477     // ideographic
478     nsGkAtoms::image_rendering,  // image-rendering
479     nsGkAtoms::in,               // in
480     nsGkAtoms::in2,              // in2
481     nsGkAtoms::intercept,        // intercept
482     // k
483     nsGkAtoms::k1,  // k1
484     nsGkAtoms::k2,  // k2
485     nsGkAtoms::k3,  // k3
486     nsGkAtoms::k4,  // k4
487     // kerning
488     nsGkAtoms::kernelMatrix,      // kernelMatrix
489     nsGkAtoms::kernelUnitLength,  // kernelUnitLength
490     nsGkAtoms::keyPoints,         // keyPoints
491     nsGkAtoms::keySplines,        // keySplines
492     nsGkAtoms::keyTimes,          // keyTimes
493     nsGkAtoms::lang,              // lang
494     // lengthAdjust
495     nsGkAtoms::letter_spacing,     // letter-spacing
496     nsGkAtoms::lighting_color,     // lighting-color
497     nsGkAtoms::limitingConeAngle,  // limitingConeAngle
498     // local
499     nsGkAtoms::marker,            // marker
500     nsGkAtoms::marker_end,        // marker-end
501     nsGkAtoms::marker_mid,        // marker-mid
502     nsGkAtoms::marker_start,      // marker-start
503     nsGkAtoms::markerHeight,      // markerHeight
504     nsGkAtoms::markerUnits,       // markerUnits
505     nsGkAtoms::markerWidth,       // markerWidth
506     nsGkAtoms::mask,              // mask
507     nsGkAtoms::maskContentUnits,  // maskContentUnits
508     nsGkAtoms::maskUnits,         // maskUnits
509     // mathematical
510     nsGkAtoms::max,          // max
511     nsGkAtoms::media,        // media
512     nsGkAtoms::method,       // method
513     nsGkAtoms::min,          // min
514     nsGkAtoms::mode,         // mode
515     nsGkAtoms::name,         // name
516     nsGkAtoms::numOctaves,   // numOctaves
517     nsGkAtoms::offset,       // offset
518     nsGkAtoms::opacity,      // opacity
519     nsGkAtoms::_operator,    // operator
520     nsGkAtoms::order,        // order
521     nsGkAtoms::orient,       // orient
522     nsGkAtoms::orientation,  // orientation
523     // origin
524     // overline-position
525     // overline-thickness
526     nsGkAtoms::overflow,  // overflow
527     // panose-1
528     nsGkAtoms::path,                 // path
529     nsGkAtoms::pathLength,           // pathLength
530     nsGkAtoms::patternContentUnits,  // patternContentUnits
531     nsGkAtoms::patternTransform,     // patternTransform
532     nsGkAtoms::patternUnits,         // patternUnits
533     nsGkAtoms::pointer_events,       // pointer-events XXX is this safe?
534     nsGkAtoms::points,               // points
535     nsGkAtoms::pointsAtX,            // pointsAtX
536     nsGkAtoms::pointsAtY,            // pointsAtY
537     nsGkAtoms::pointsAtZ,            // pointsAtZ
538     nsGkAtoms::preserveAlpha,        // preserveAlpha
539     nsGkAtoms::preserveAspectRatio,  // preserveAspectRatio
540     nsGkAtoms::primitiveUnits,       // primitiveUnits
541     nsGkAtoms::r,                    // r
542     nsGkAtoms::radius,               // radius
543     nsGkAtoms::refX,                 // refX
544     nsGkAtoms::refY,                 // refY
545     nsGkAtoms::repeatCount,          // repeatCount
546     nsGkAtoms::repeatDur,            // repeatDur
547     nsGkAtoms::requiredExtensions,   // requiredExtensions
548     nsGkAtoms::requiredFeatures,     // requiredFeatures
549     nsGkAtoms::restart,              // restart
550     nsGkAtoms::result,               // result
551     nsGkAtoms::rotate,               // rotate
552     nsGkAtoms::rx,                   // rx
553     nsGkAtoms::ry,                   // ry
554     nsGkAtoms::scale,                // scale
555     nsGkAtoms::seed,                 // seed
556     nsGkAtoms::shape_rendering,      // shape-rendering
557     nsGkAtoms::slope,                // slope
558     nsGkAtoms::spacing,              // spacing
559     nsGkAtoms::specularConstant,     // specularConstant
560     nsGkAtoms::specularExponent,     // specularExponent
561     nsGkAtoms::spreadMethod,         // spreadMethod
562     nsGkAtoms::startOffset,          // startOffset
563     nsGkAtoms::stdDeviation,         // stdDeviation
564     // stemh
565     // stemv
566     nsGkAtoms::stitchTiles,   // stitchTiles
567     nsGkAtoms::stop_color,    // stop-color
568     nsGkAtoms::stop_opacity,  // stop-opacity
569     // strikethrough-position
570     // strikethrough-thickness
571     nsGkAtoms::string,             // string
572     nsGkAtoms::stroke,             // stroke
573     nsGkAtoms::stroke_dasharray,   // stroke-dasharray
574     nsGkAtoms::stroke_dashoffset,  // stroke-dashoffset
575     nsGkAtoms::stroke_linecap,     // stroke-linecap
576     nsGkAtoms::stroke_linejoin,    // stroke-linejoin
577     nsGkAtoms::stroke_miterlimit,  // stroke-miterlimit
578     nsGkAtoms::stroke_opacity,     // stroke-opacity
579     nsGkAtoms::stroke_width,       // stroke-width
580     nsGkAtoms::surfaceScale,       // surfaceScale
581     nsGkAtoms::systemLanguage,     // systemLanguage
582     nsGkAtoms::tableValues,        // tableValues
583     nsGkAtoms::target,             // target
584     nsGkAtoms::targetX,            // targetX
585     nsGkAtoms::targetY,            // targetY
586     nsGkAtoms::text_anchor,        // text-anchor
587     nsGkAtoms::text_decoration,    // text-decoration
588     // textLength
589     nsGkAtoms::text_rendering,    // text-rendering
590     nsGkAtoms::title,             // title
591     nsGkAtoms::to,                // to
592     nsGkAtoms::transform,         // transform
593     nsGkAtoms::transform_origin,  // transform-origin
594     nsGkAtoms::type,              // type
595     // u1
596     // u2
597     // underline-position
598     // underline-thickness
599     // unicode
600     nsGkAtoms::unicode_bidi,  // unicode-bidi
601     // unicode-range
602     // units-per-em
603     // v-alphabetic
604     // v-hanging
605     // v-ideographic
606     // v-mathematical
607     nsGkAtoms::values,         // values
608     nsGkAtoms::vector_effect,  // vector-effect
609     // vert-adv-y
610     // vert-origin-x
611     // vert-origin-y
612     nsGkAtoms::viewBox,     // viewBox
613     nsGkAtoms::viewTarget,  // viewTarget
614     nsGkAtoms::visibility,  // visibility
615     nsGkAtoms::width,       // width
616     // widths
617     nsGkAtoms::word_spacing,  // word-spacing
618     nsGkAtoms::writing_mode,  // writing-mode
619     nsGkAtoms::x,             // x
620     // x-height
621     nsGkAtoms::x1,                // x1
622     nsGkAtoms::x2,                // x2
623     nsGkAtoms::xChannelSelector,  // xChannelSelector
624     nsGkAtoms::y,                 // y
625     nsGkAtoms::y1,                // y1
626     nsGkAtoms::y2,                // y2
627     nsGkAtoms::yChannelSelector,  // yChannelSelector
628     nsGkAtoms::z,                 // z
629     nsGkAtoms::zoomAndPan,        // zoomAndPan
630     nullptr};
631 
632 constexpr const nsStaticAtom* const kURLAttributesSVG[] = {nsGkAtoms::href,
633                                                            nullptr};
634 
635 static_assert(AllOf(std::begin(kURLAttributesSVG), std::end(kURLAttributesSVG),
__anonf3c3a9f30102(auto aURLAttributeSVG) 636                     [](auto aURLAttributeSVG) {
637                       return AnyOf(std::begin(kAttributesSVG),
638                                    std::end(kAttributesSVG),
639                                    [&](auto aAttributeSVG) {
640                                      return aAttributeSVG == aURLAttributeSVG;
641                                    });
642                     }));
643 
644 const nsStaticAtom* const kElementsMathML[] = {
645     nsGkAtoms::abs_,                  // abs
646     nsGkAtoms::_and,                  // and
647     nsGkAtoms::annotation_,           // annotation
648     nsGkAtoms::annotation_xml_,       // annotation-xml
649     nsGkAtoms::apply_,                // apply
650     nsGkAtoms::approx_,               // approx
651     nsGkAtoms::arccos_,               // arccos
652     nsGkAtoms::arccosh_,              // arccosh
653     nsGkAtoms::arccot_,               // arccot
654     nsGkAtoms::arccoth_,              // arccoth
655     nsGkAtoms::arccsc_,               // arccsc
656     nsGkAtoms::arccsch_,              // arccsch
657     nsGkAtoms::arcsec_,               // arcsec
658     nsGkAtoms::arcsech_,              // arcsech
659     nsGkAtoms::arcsin_,               // arcsin
660     nsGkAtoms::arcsinh_,              // arcsinh
661     nsGkAtoms::arctan_,               // arctan
662     nsGkAtoms::arctanh_,              // arctanh
663     nsGkAtoms::arg_,                  // arg
664     nsGkAtoms::bind_,                 // bind
665     nsGkAtoms::bvar_,                 // bvar
666     nsGkAtoms::card_,                 // card
667     nsGkAtoms::cartesianproduct_,     // cartesianproduct
668     nsGkAtoms::cbytes_,               // cbytes
669     nsGkAtoms::ceiling,               // ceiling
670     nsGkAtoms::cerror_,               // cerror
671     nsGkAtoms::ci_,                   // ci
672     nsGkAtoms::cn_,                   // cn
673     nsGkAtoms::codomain_,             // codomain
674     nsGkAtoms::complexes_,            // complexes
675     nsGkAtoms::compose_,              // compose
676     nsGkAtoms::condition_,            // condition
677     nsGkAtoms::conjugate_,            // conjugate
678     nsGkAtoms::cos_,                  // cos
679     nsGkAtoms::cosh_,                 // cosh
680     nsGkAtoms::cot_,                  // cot
681     nsGkAtoms::coth_,                 // coth
682     nsGkAtoms::cs_,                   // cs
683     nsGkAtoms::csc_,                  // csc
684     nsGkAtoms::csch_,                 // csch
685     nsGkAtoms::csymbol_,              // csymbol
686     nsGkAtoms::curl_,                 // curl
687     nsGkAtoms::declare,               // declare
688     nsGkAtoms::degree_,               // degree
689     nsGkAtoms::determinant_,          // determinant
690     nsGkAtoms::diff_,                 // diff
691     nsGkAtoms::divergence_,           // divergence
692     nsGkAtoms::divide_,               // divide
693     nsGkAtoms::domain_,               // domain
694     nsGkAtoms::domainofapplication_,  // domainofapplication
695     nsGkAtoms::el,                    // el
696     nsGkAtoms::emptyset_,             // emptyset
697     nsGkAtoms::eq_,                   // eq
698     nsGkAtoms::equivalent_,           // equivalent
699     nsGkAtoms::eulergamma_,           // eulergamma
700     nsGkAtoms::exists_,               // exists
701     nsGkAtoms::exp_,                  // exp
702     nsGkAtoms::exponentiale_,         // exponentiale
703     nsGkAtoms::factorial_,            // factorial
704     nsGkAtoms::factorof_,             // factorof
705     nsGkAtoms::_false,                // false
706     nsGkAtoms::floor,                 // floor
707     nsGkAtoms::fn_,                   // fn
708     nsGkAtoms::forall_,               // forall
709     nsGkAtoms::gcd_,                  // gcd
710     nsGkAtoms::geq_,                  // geq
711     nsGkAtoms::grad,                  // grad
712     nsGkAtoms::gt_,                   // gt
713     nsGkAtoms::ident_,                // ident
714     nsGkAtoms::image,                 // image
715     nsGkAtoms::imaginary_,            // imaginary
716     nsGkAtoms::imaginaryi_,           // imaginaryi
717     nsGkAtoms::implies_,              // implies
718     nsGkAtoms::in,                    // in
719     nsGkAtoms::infinity,              // infinity
720     nsGkAtoms::int_,                  // int
721     nsGkAtoms::integers_,             // integers
722     nsGkAtoms::intersect_,            // intersect
723     nsGkAtoms::interval_,             // interval
724     nsGkAtoms::inverse_,              // inverse
725     nsGkAtoms::lambda_,               // lambda
726     nsGkAtoms::laplacian_,            // laplacian
727     nsGkAtoms::lcm_,                  // lcm
728     nsGkAtoms::leq_,                  // leq
729     nsGkAtoms::limit_,                // limit
730     nsGkAtoms::list_,                 // list
731     nsGkAtoms::ln_,                   // ln
732     nsGkAtoms::log_,                  // log
733     nsGkAtoms::logbase_,              // logbase
734     nsGkAtoms::lowlimit_,             // lowlimit
735     nsGkAtoms::lt_,                   // lt
736     nsGkAtoms::maction_,              // maction
737     nsGkAtoms::maligngroup_,          // maligngroup
738     nsGkAtoms::malignmark_,           // malignmark
739     nsGkAtoms::math,                  // math
740     nsGkAtoms::matrix,                // matrix
741     nsGkAtoms::matrixrow_,            // matrixrow
742     nsGkAtoms::max,                   // max
743     nsGkAtoms::mean_,                 // mean
744     nsGkAtoms::median_,               // median
745     nsGkAtoms::menclose_,             // menclose
746     nsGkAtoms::merror_,               // merror
747     nsGkAtoms::mfenced_,              // mfenced
748     nsGkAtoms::mfrac_,                // mfrac
749     nsGkAtoms::mglyph_,               // mglyph
750     nsGkAtoms::mi_,                   // mi
751     nsGkAtoms::min,                   // min
752     nsGkAtoms::minus_,                // minus
753     nsGkAtoms::mlabeledtr_,           // mlabeledtr
754     nsGkAtoms::mlongdiv_,             // mlongdiv
755     nsGkAtoms::mmultiscripts_,        // mmultiscripts
756     nsGkAtoms::mn_,                   // mn
757     nsGkAtoms::mo_,                   // mo
758     nsGkAtoms::mode,                  // mode
759     nsGkAtoms::moment_,               // moment
760     nsGkAtoms::momentabout_,          // momentabout
761     nsGkAtoms::mover_,                // mover
762     nsGkAtoms::mpadded_,              // mpadded
763     nsGkAtoms::mphantom_,             // mphantom
764     nsGkAtoms::mprescripts_,          // mprescripts
765     nsGkAtoms::mroot_,                // mroot
766     nsGkAtoms::mrow_,                 // mrow
767     nsGkAtoms::ms_,                   // ms
768     nsGkAtoms::mscarries_,            // mscarries
769     nsGkAtoms::mscarry_,              // mscarry
770     nsGkAtoms::msgroup_,              // msgroup
771     nsGkAtoms::msline_,               // msline
772     nsGkAtoms::mspace_,               // mspace
773     nsGkAtoms::msqrt_,                // msqrt
774     nsGkAtoms::msrow_,                // msrow
775     nsGkAtoms::mstack_,               // mstack
776     nsGkAtoms::mstyle_,               // mstyle
777     nsGkAtoms::msub_,                 // msub
778     nsGkAtoms::msubsup_,              // msubsup
779     nsGkAtoms::msup_,                 // msup
780     nsGkAtoms::mtable_,               // mtable
781     nsGkAtoms::mtd_,                  // mtd
782     nsGkAtoms::mtext_,                // mtext
783     nsGkAtoms::mtr_,                  // mtr
784     nsGkAtoms::munder_,               // munder
785     nsGkAtoms::munderover_,           // munderover
786     nsGkAtoms::naturalnumbers_,       // naturalnumbers
787     nsGkAtoms::neq_,                  // neq
788     nsGkAtoms::none,                  // none
789     nsGkAtoms::_not,                  // not
790     nsGkAtoms::notanumber_,           // notanumber
791     nsGkAtoms::note_,                 // note
792     nsGkAtoms::notin_,                // notin
793     nsGkAtoms::notprsubset_,          // notprsubset
794     nsGkAtoms::notsubset_,            // notsubset
795     nsGkAtoms::_or,                   // or
796     nsGkAtoms::otherwise,             // otherwise
797     nsGkAtoms::outerproduct_,         // outerproduct
798     nsGkAtoms::partialdiff_,          // partialdiff
799     nsGkAtoms::pi_,                   // pi
800     nsGkAtoms::piece_,                // piece
801     nsGkAtoms::piecewise_,            // piecewise
802     nsGkAtoms::plus_,                 // plus
803     nsGkAtoms::power_,                // power
804     nsGkAtoms::primes_,               // primes
805     nsGkAtoms::product_,              // product
806     nsGkAtoms::prsubset_,             // prsubset
807     nsGkAtoms::quotient_,             // quotient
808     nsGkAtoms::rationals_,            // rationals
809     nsGkAtoms::real_,                 // real
810     nsGkAtoms::reals_,                // reals
811     nsGkAtoms::reln_,                 // reln
812     nsGkAtoms::rem,                   // rem
813     nsGkAtoms::root_,                 // root
814     nsGkAtoms::scalarproduct_,        // scalarproduct
815     nsGkAtoms::sdev_,                 // sdev
816     nsGkAtoms::sec_,                  // sec
817     nsGkAtoms::sech_,                 // sech
818     nsGkAtoms::selector_,             // selector
819     nsGkAtoms::semantics_,            // semantics
820     nsGkAtoms::sep_,                  // sep
821     nsGkAtoms::set,                   // set
822     nsGkAtoms::setdiff_,              // setdiff
823     nsGkAtoms::share_,                // share
824     nsGkAtoms::sin_,                  // sin
825     nsGkAtoms::sinh_,                 // sinh
826     nsGkAtoms::subset_,               // subset
827     nsGkAtoms::sum,                   // sum
828     nsGkAtoms::tan_,                  // tan
829     nsGkAtoms::tanh_,                 // tanh
830     nsGkAtoms::tendsto_,              // tendsto
831     nsGkAtoms::times_,                // times
832     nsGkAtoms::transpose_,            // transpose
833     nsGkAtoms::_true,                 // true
834     nsGkAtoms::union_,                // union
835     nsGkAtoms::uplimit_,              // uplimit
836     nsGkAtoms::variance_,             // variance
837     nsGkAtoms::vector_,               // vector
838     nsGkAtoms::vectorproduct_,        // vectorproduct
839     nsGkAtoms::xor_,                  // xor
840     nullptr};
841 
842 const nsStaticAtom* const kAttributesMathML[] = {
843     nsGkAtoms::accent_,                // accent
844     nsGkAtoms::accentunder_,           // accentunder
845     nsGkAtoms::actiontype_,            // actiontype
846     nsGkAtoms::align,                  // align
847     nsGkAtoms::alignmentscope_,        // alignmentscope
848     nsGkAtoms::alt,                    // alt
849     nsGkAtoms::altimg_,                // altimg
850     nsGkAtoms::altimg_height_,         // altimg-height
851     nsGkAtoms::altimg_valign_,         // altimg-valign
852     nsGkAtoms::altimg_width_,          // altimg-width
853     nsGkAtoms::background,             // background
854     nsGkAtoms::base,                   // base
855     nsGkAtoms::bevelled_,              // bevelled
856     nsGkAtoms::cd_,                    // cd
857     nsGkAtoms::cdgroup_,               // cdgroup
858     nsGkAtoms::charalign_,             // charalign
859     nsGkAtoms::close,                  // close
860     nsGkAtoms::closure_,               // closure
861     nsGkAtoms::color,                  // color
862     nsGkAtoms::columnalign_,           // columnalign
863     nsGkAtoms::columnalignment_,       // columnalignment
864     nsGkAtoms::columnlines_,           // columnlines
865     nsGkAtoms::columnspacing_,         // columnspacing
866     nsGkAtoms::columnspan_,            // columnspan
867     nsGkAtoms::columnwidth_,           // columnwidth
868     nsGkAtoms::crossout_,              // crossout
869     nsGkAtoms::decimalpoint_,          // decimalpoint
870     nsGkAtoms::definitionURL_,         // definitionURL
871     nsGkAtoms::denomalign_,            // denomalign
872     nsGkAtoms::depth_,                 // depth
873     nsGkAtoms::dir,                    // dir
874     nsGkAtoms::display,                // display
875     nsGkAtoms::displaystyle_,          // displaystyle
876     nsGkAtoms::edge_,                  // edge
877     nsGkAtoms::encoding,               // encoding
878     nsGkAtoms::equalcolumns_,          // equalcolumns
879     nsGkAtoms::equalrows_,             // equalrows
880     nsGkAtoms::fence_,                 // fence
881     nsGkAtoms::fontfamily_,            // fontfamily
882     nsGkAtoms::fontsize_,              // fontsize
883     nsGkAtoms::fontstyle_,             // fontstyle
884     nsGkAtoms::fontweight_,            // fontweight
885     nsGkAtoms::form,                   // form
886     nsGkAtoms::frame,                  // frame
887     nsGkAtoms::framespacing_,          // framespacing
888     nsGkAtoms::groupalign_,            // groupalign
889     nsGkAtoms::height,                 // height
890     nsGkAtoms::href,                   // href
891     nsGkAtoms::id,                     // id
892     nsGkAtoms::indentalign_,           // indentalign
893     nsGkAtoms::indentalignfirst_,      // indentalignfirst
894     nsGkAtoms::indentalignlast_,       // indentalignlast
895     nsGkAtoms::indentshift_,           // indentshift
896     nsGkAtoms::indentshiftfirst_,      // indentshiftfirst
897     nsGkAtoms::indenttarget_,          // indenttarget
898     nsGkAtoms::index,                  // index
899     nsGkAtoms::integer,                // integer
900     nsGkAtoms::largeop_,               // largeop
901     nsGkAtoms::length,                 // length
902     nsGkAtoms::linebreak_,             // linebreak
903     nsGkAtoms::linebreakmultchar_,     // linebreakmultchar
904     nsGkAtoms::linebreakstyle_,        // linebreakstyle
905     nsGkAtoms::linethickness_,         // linethickness
906     nsGkAtoms::location_,              // location
907     nsGkAtoms::longdivstyle_,          // longdivstyle
908     nsGkAtoms::lquote_,                // lquote
909     nsGkAtoms::lspace_,                // lspace
910     nsGkAtoms::ltr,                    // ltr
911     nsGkAtoms::mathbackground_,        // mathbackground
912     nsGkAtoms::mathcolor_,             // mathcolor
913     nsGkAtoms::mathsize_,              // mathsize
914     nsGkAtoms::mathvariant_,           // mathvariant
915     nsGkAtoms::maxsize_,               // maxsize
916     nsGkAtoms::minlabelspacing_,       // minlabelspacing
917     nsGkAtoms::minsize_,               // minsize
918     nsGkAtoms::movablelimits_,         // movablelimits
919     nsGkAtoms::msgroup_,               // msgroup
920     nsGkAtoms::name,                   // name
921     nsGkAtoms::newline,                // newline
922     nsGkAtoms::notation_,              // notation
923     nsGkAtoms::numalign_,              // numalign
924     nsGkAtoms::number,                 // number
925     nsGkAtoms::open,                   // open
926     nsGkAtoms::order,                  // order
927     nsGkAtoms::other,                  // other
928     nsGkAtoms::overflow,               // overflow
929     nsGkAtoms::position,               // position
930     nsGkAtoms::role,                   // role
931     nsGkAtoms::rowalign_,              // rowalign
932     nsGkAtoms::rowlines_,              // rowlines
933     nsGkAtoms::rowspacing_,            // rowspacing
934     nsGkAtoms::rowspan,                // rowspan
935     nsGkAtoms::rquote_,                // rquote
936     nsGkAtoms::rspace_,                // rspace
937     nsGkAtoms::schemaLocation_,        // schemaLocation
938     nsGkAtoms::scriptlevel_,           // scriptlevel
939     nsGkAtoms::scriptminsize_,         // scriptminsize
940     nsGkAtoms::scriptsize_,            // scriptsize
941     nsGkAtoms::scriptsizemultiplier_,  // scriptsizemultiplier
942     nsGkAtoms::selection_,             // selection
943     nsGkAtoms::separator_,             // separator
944     nsGkAtoms::separators_,            // separators
945     nsGkAtoms::shift_,                 // shift
946     nsGkAtoms::side_,                  // side
947     nsGkAtoms::src,                    // src
948     nsGkAtoms::stackalign_,            // stackalign
949     nsGkAtoms::stretchy_,              // stretchy
950     nsGkAtoms::subscriptshift_,        // subscriptshift
951     nsGkAtoms::superscriptshift_,      // superscriptshift
952     nsGkAtoms::symmetric_,             // symmetric
953     nsGkAtoms::type,                   // type
954     nsGkAtoms::voffset_,               // voffset
955     nsGkAtoms::width,                  // width
956     nsGkAtoms::xref_,                  // xref
957     nullptr};
958 
959 const nsStaticAtom* const kURLAttributesMathML[] = {
960     // clang-format off
961   nsGkAtoms::href,
962   nsGkAtoms::src,
963   nsGkAtoms::cdgroup_,
964   nsGkAtoms::altimg_,
965   nsGkAtoms::definitionURL_,
966   nullptr
967     // clang-format on
968 };
969 
970 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sElementsHTML = nullptr;
971 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sAttributesHTML = nullptr;
972 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sPresAttributesHTML = nullptr;
973 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sElementsSVG = nullptr;
974 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sAttributesSVG = nullptr;
975 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sElementsMathML = nullptr;
976 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sAttributesMathML = nullptr;
977 nsIPrincipal* nsTreeSanitizer::sNullPrincipal = nullptr;
978 
nsTreeSanitizer(uint32_t aFlags)979 nsTreeSanitizer::nsTreeSanitizer(uint32_t aFlags)
980     : mAllowStyles(aFlags & nsIParserUtils::SanitizerAllowStyle),
981       mAllowComments(aFlags & nsIParserUtils::SanitizerAllowComments),
982       mDropNonCSSPresentation(aFlags &
983                               nsIParserUtils::SanitizerDropNonCSSPresentation),
984       mDropForms(aFlags & nsIParserUtils::SanitizerDropForms),
985       mCidEmbedsOnly(aFlags & nsIParserUtils::SanitizerCidEmbedsOnly),
986       mDropMedia(aFlags & nsIParserUtils::SanitizerDropMedia),
987       mFullDocument(false),
988       mLogRemovals(aFlags & nsIParserUtils::SanitizerLogRemovals),
989       mOnlyConditionalCSS(aFlags &
990                           nsIParserUtils::SanitizerRemoveOnlyConditionalCSS) {
991   if (mCidEmbedsOnly) {
992     // Sanitizing styles for external references is not supported.
993     mAllowStyles = false;
994   }
995 
996   mAllowedElements = nullptr;
997   mBlockedElements = nullptr;
998 
999   if (!sElementsHTML) {
1000     // Initialize lazily to avoid having to initialize at all if the user
1001     // doesn't paste HTML or load feeds.
1002     InitializeStatics();
1003   }
1004   /* Ensure SanitizerRemoveOnlyConditionalCSS isn't combined with any
1005    * flags, except SanitizerLogRemovals. */
1006   MOZ_ASSERT(!mOnlyConditionalCSS ||
1007              0 ==
1008                  (aFlags & ~(nsIParserUtils::SanitizerRemoveOnlyConditionalCSS |
1009                              nsIParserUtils::SanitizerLogRemovals)));
1010 }
1011 
MustFlatten(int32_t aNamespace,nsAtom * aLocal)1012 bool nsTreeSanitizer::MustFlatten(int32_t aNamespace, nsAtom* aLocal) {
1013   if (aNamespace == kNameSpaceID_XHTML) {
1014     if (mIsCustomized) {
1015       // TODO(freddy): Make it work for other namespaces.
1016       // See https://github.com/WICG/sanitizer-api/issues/72
1017       return ((mAllowedElements && !mAllowedElements->Contains(aLocal)) ||
1018               ((mBlockedElements && mBlockedElements->Contains(aLocal))));
1019     }
1020     if (mDropNonCSSPresentation &&
1021         (nsGkAtoms::font == aLocal || nsGkAtoms::center == aLocal)) {
1022       return true;
1023     }
1024     if (mDropForms &&
1025         (nsGkAtoms::form == aLocal || nsGkAtoms::input == aLocal ||
1026          nsGkAtoms::option == aLocal || nsGkAtoms::optgroup == aLocal)) {
1027       return true;
1028     }
1029     if (mFullDocument &&
1030         (nsGkAtoms::title == aLocal || nsGkAtoms::html == aLocal ||
1031          nsGkAtoms::head == aLocal || nsGkAtoms::body == aLocal)) {
1032       return false;
1033     }
1034     if (nsGkAtoms::_template == aLocal) {
1035       return false;
1036     }
1037     return !sElementsHTML->Contains(aLocal);
1038   }
1039   if (aNamespace == kNameSpaceID_SVG) {
1040     if (mCidEmbedsOnly || mDropMedia) {
1041       // Sanitizing CSS-based URL references inside SVG presentational
1042       // attributes is not supported, so flattening for cid: embed case.
1043       return true;
1044     }
1045     return !sElementsSVG->Contains(aLocal);
1046   }
1047   if (aNamespace == kNameSpaceID_MathML) {
1048     return !sElementsMathML->Contains(aLocal);
1049   }
1050   return true;
1051 }
1052 
IsURL(const nsStaticAtom * const * aURLs,nsAtom * aLocalName)1053 bool nsTreeSanitizer::IsURL(const nsStaticAtom* const* aURLs,
1054                             nsAtom* aLocalName) {
1055   const nsStaticAtom* atom;
1056   while ((atom = *aURLs)) {
1057     if (atom == aLocalName) {
1058       return true;
1059     }
1060     ++aURLs;
1061   }
1062   return false;
1063 }
1064 
MustPrune(int32_t aNamespace,nsAtom * aLocal,mozilla::dom::Element * aElement)1065 bool nsTreeSanitizer::MustPrune(int32_t aNamespace, nsAtom* aLocal,
1066                                 mozilla::dom::Element* aElement) {
1067   // To avoid attacks where a MathML script becomes something that gets
1068   // serialized in a way that it parses back as an HTML script, let's just
1069   // drop elements with the local name 'script' regardless of namespace.
1070   if (nsGkAtoms::script == aLocal) {
1071     return true;
1072   }
1073   if (aNamespace == kNameSpaceID_XHTML) {
1074     if (nsGkAtoms::title == aLocal && !mFullDocument) {
1075       // emulate the quirks of the old parser
1076       return true;
1077     }
1078     if (mDropForms &&
1079         (nsGkAtoms::select == aLocal || nsGkAtoms::button == aLocal ||
1080          nsGkAtoms::datalist == aLocal)) {
1081       return true;
1082     }
1083     if (mDropMedia &&
1084         (nsGkAtoms::img == aLocal || nsGkAtoms::video == aLocal ||
1085          nsGkAtoms::audio == aLocal || nsGkAtoms::source == aLocal)) {
1086       return true;
1087     }
1088     if (nsGkAtoms::meta == aLocal &&
1089         (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::charset) ||
1090          aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv))) {
1091       // Throw away charset declarations even if they also have microdata
1092       // which they can't validly have.
1093       return true;
1094     }
1095     if (((!mFullDocument && nsGkAtoms::meta == aLocal) ||
1096          nsGkAtoms::link == aLocal) &&
1097         !(aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::itemprop) ||
1098           aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::itemscope))) {
1099       // emulate old behavior for non-Microdata <meta> and <link> presumably
1100       // in <head>. <meta> and <link> are whitelisted in order to avoid
1101       // corrupting Microdata when they appear in <body>. Note that
1102       // SanitizeAttributes() will remove the rel attribute from <link> and
1103       // the name attribute from <meta>.
1104       return true;
1105     }
1106   }
1107   if (mAllowStyles) {
1108     return nsGkAtoms::style == aLocal && !(aNamespace == kNameSpaceID_XHTML ||
1109                                            aNamespace == kNameSpaceID_SVG);
1110   }
1111   if (nsGkAtoms::style == aLocal) {
1112     return true;
1113   }
1114   return false;
1115 }
1116 
SanitizeStyleSheet(const nsAString & aOriginal,nsAString & aSanitized,Document * aDocument,nsIURI * aBaseURI)1117 void nsTreeSanitizer::SanitizeStyleSheet(const nsAString& aOriginal,
1118                                          nsAString& aSanitized,
1119                                          Document* aDocument,
1120                                          nsIURI* aBaseURI) {
1121   aSanitized.Truncate();
1122 
1123   NS_ConvertUTF16toUTF8 style(aOriginal);
1124   RefPtr<nsIReferrerInfo> referrer =
1125       ReferrerInfo::CreateForInternalCSSResources(aDocument);
1126   auto extraData =
1127       MakeRefPtr<URLExtraData>(aBaseURI, referrer, aDocument->NodePrincipal());
1128   auto sanitizationKind = mOnlyConditionalCSS
1129                               ? StyleSanitizationKind::NoConditionalRules
1130                               : StyleSanitizationKind::Standard;
1131   RefPtr<RawServoStyleSheetContents> contents =
1132       Servo_StyleSheet_FromUTF8Bytes(
1133           /* loader = */ nullptr,
1134           /* stylesheet = */ nullptr,
1135           /* load_data = */ nullptr, &style,
1136           css::SheetParsingMode::eAuthorSheetFeatures, extraData.get(),
1137           /* line_number_offset = */ 0, aDocument->GetCompatibilityMode(),
1138           /* reusable_sheets = */ nullptr,
1139           /* use_counters = */ nullptr, StyleAllowImportRules::Yes,
1140           sanitizationKind, &aSanitized)
1141           .Consume();
1142 
1143   if (mLogRemovals && aSanitized.Length() != aOriginal.Length()) {
1144     LogMessage("Removed some rules and/or properties from stylesheet.",
1145                aDocument);
1146   }
1147 }
1148 
1149 template <size_t Len>
UTF16StringStartsWith(const char16_t * aStr,uint32_t aLength,const char16_t (& aNeedle)[Len])1150 static bool UTF16StringStartsWith(const char16_t* aStr, uint32_t aLength,
1151                                   const char16_t (&aNeedle)[Len]) {
1152   MOZ_ASSERT(aNeedle[Len - 1] == '\0',
1153              "needle should be a UTF-16 encoded string literal");
1154 
1155   if (aLength < Len - 1) {
1156     return false;
1157   }
1158   for (size_t i = 0; i < Len - 1; i++) {
1159     if (aStr[i] != aNeedle[i]) {
1160       return false;
1161     }
1162   }
1163   return true;
1164 }
1165 
SanitizeAttributes(mozilla::dom::Element * aElement,AllowedAttributes aAllowed)1166 void nsTreeSanitizer::SanitizeAttributes(mozilla::dom::Element* aElement,
1167                                          AllowedAttributes aAllowed) {
1168   int32_t ac = (int)aElement->GetAttrCount();
1169 
1170   for (int32_t i = ac - 1; i >= 0; --i) {
1171     const nsAttrName* attrName = aElement->GetAttrNameAt(i);
1172     int32_t attrNs = attrName->NamespaceID();
1173     RefPtr<nsAtom> attrLocal = attrName->LocalName();
1174 
1175     if (mIsCustomized) {
1176       bool shouldRemove = true;
1177       RefPtr<nsAtom> elemName = aElement->NodeInfo()->NameAtom();
1178 
1179       // check allow list
1180       if (mAllowedAttributes) {
1181         auto allowedElements = mAllowedAttributes->Lookup(attrLocal);
1182         if (allowedElements) {
1183           if (allowedElements.Data()->Contains(elemName) ||
1184               allowedElements.Data()->Contains(nsGkAtoms::_asterisk)) {
1185             shouldRemove = false;
1186           }
1187         }
1188       }
1189       // checking drop list last
1190       // i.e., if listd as both allowed and dropped, it will still be dropped
1191       if (mDroppedAttributes) {
1192         auto dropElements = mDroppedAttributes->Lookup(attrLocal);
1193         if (dropElements) {
1194           if (dropElements.Data()->Contains(elemName) ||
1195               dropElements.Data()->Contains(nsGkAtoms::_asterisk)) {
1196             shouldRemove = true;
1197           }
1198         }
1199       }
1200       if (shouldRemove) {
1201         aElement->UnsetAttr(kNameSpaceID_None, attrLocal, false);
1202         // in case the attribute removal shuffled the attribute order, start
1203         // the loop again.
1204         --ac;
1205         i = ac;  // i will be decremented immediately thanks to the for loop
1206       }
1207       continue;
1208     }
1209 
1210     if (kNameSpaceID_None == attrNs) {
1211       if (aAllowed.mStyle && nsGkAtoms::style == attrLocal) {
1212         continue;
1213       }
1214       if (aAllowed.mDangerousSrc && nsGkAtoms::src == attrLocal) {
1215         continue;
1216       }
1217       if (IsURL(aAllowed.mURLs, attrLocal)) {
1218         if (SanitizeURL(aElement, attrNs, attrLocal)) {
1219           // in case the attribute removal shuffled the attribute order, start
1220           // the loop again.
1221           --ac;
1222           i = ac;  // i will be decremented immediately thanks to the for loop
1223           continue;
1224         }
1225         // else fall through to see if there's another reason to drop this
1226         // attribute (in particular if the attribute is background="" on an
1227         // HTML element)
1228       }
1229       if (!mDropNonCSSPresentation &&
1230           (aAllowed.mNames == sAttributesHTML) &&  // element is HTML
1231           sPresAttributesHTML->Contains(attrLocal)) {
1232         continue;
1233       }
1234       if (aAllowed.mNames->Contains(attrLocal) &&
1235           !((attrLocal == nsGkAtoms::rel &&
1236              aElement->IsHTMLElement(nsGkAtoms::link)) ||
1237             (!mFullDocument && attrLocal == nsGkAtoms::name &&
1238              aElement->IsHTMLElement(nsGkAtoms::meta)))) {
1239         // name="" and rel="" are whitelisted, but treat them as blacklisted
1240         // for <meta name> (fragment case) and <link rel> (all cases) to avoid
1241         // document-wide metadata or styling overrides with non-conforming
1242         // <meta name itemprop> or
1243         // <link rel itemprop>
1244         continue;
1245       }
1246       const char16_t* localStr = attrLocal->GetUTF16String();
1247       uint32_t localLen = attrLocal->GetLength();
1248       // Allow underscore to cater to the MCE editor library.
1249       // Allow data-* on SVG and MathML, too, as a forward-compat measure.
1250       // Allow aria-* on all for simplicity.
1251       if (UTF16StringStartsWith(localStr, localLen, u"_") ||
1252           UTF16StringStartsWith(localStr, localLen, u"data-") ||
1253           UTF16StringStartsWith(localStr, localLen, u"aria-")) {
1254         continue;
1255       }
1256       // else not allowed
1257     } else if (kNameSpaceID_XML == attrNs) {
1258       if (nsGkAtoms::lang == attrLocal || nsGkAtoms::space == attrLocal) {
1259         continue;
1260       }
1261       // else not allowed
1262     } else if (aAllowed.mXLink && kNameSpaceID_XLink == attrNs) {
1263       if (nsGkAtoms::href == attrLocal) {
1264         if (SanitizeURL(aElement, attrNs, attrLocal)) {
1265           // in case the attribute removal shuffled the attribute order, start
1266           // the loop again.
1267           --ac;
1268           i = ac;  // i will be decremented immediately thanks to the for loop
1269         }
1270         continue;
1271       }
1272       if (nsGkAtoms::type == attrLocal || nsGkAtoms::title == attrLocal ||
1273           nsGkAtoms::show == attrLocal || nsGkAtoms::actuate == attrLocal) {
1274         continue;
1275       }
1276       // else not allowed
1277     }
1278     aElement->UnsetAttr(kNameSpaceID_None, attrLocal, false);
1279     if (mLogRemovals) {
1280       LogMessage("Removed unsafe attribute.", aElement->OwnerDoc(), aElement,
1281                  attrLocal);
1282     }
1283     // in case the attribute removal shuffled the attribute order, start the
1284     // loop again.
1285     --ac;
1286     i = ac;  // i will be decremented immediately thanks to the for loop
1287   }
1288 
1289   // If we've got HTML audio or video, add the controls attribute, because
1290   // otherwise the content is unplayable with scripts removed.
1291   if (aElement->IsAnyOfHTMLElements(nsGkAtoms::video, nsGkAtoms::audio)) {
1292     aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::controls, u""_ns, false);
1293   }
1294 }
1295 
SanitizeURL(mozilla::dom::Element * aElement,int32_t aNamespace,nsAtom * aLocalName)1296 bool nsTreeSanitizer::SanitizeURL(mozilla::dom::Element* aElement,
1297                                   int32_t aNamespace, nsAtom* aLocalName) {
1298   nsAutoString value;
1299   aElement->GetAttr(aNamespace, aLocalName, value);
1300 
1301   // Get value and remove mandatory quotes
1302   static const char* kWhitespace = "\n\r\t\b";
1303   const nsAString& v = nsContentUtils::TrimCharsInSet(kWhitespace, value);
1304   // Fragment-only url cannot be harmful.
1305   if (!v.IsEmpty() && v.First() == u'#') {
1306     return false;
1307   }
1308 
1309   nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
1310   uint32_t flags = nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL;
1311 
1312   nsCOMPtr<nsIURI> attrURI;
1313   nsresult rv =
1314       NS_NewURI(getter_AddRefs(attrURI), v, nullptr, aElement->GetBaseURI());
1315   if (NS_SUCCEEDED(rv)) {
1316     if (mCidEmbedsOnly && kNameSpaceID_None == aNamespace) {
1317       if (nsGkAtoms::src == aLocalName || nsGkAtoms::background == aLocalName) {
1318         // comm-central uses a hack that makes nsIURIs created with cid: specs
1319         // actually have an about:blank spec. Therefore, nsIURI facilities are
1320         // useless for cid: when comm-central code is participating.
1321         if (!(v.Length() > 4 && (v[0] == 'c' || v[0] == 'C') &&
1322               (v[1] == 'i' || v[1] == 'I') && (v[2] == 'd' || v[2] == 'D') &&
1323               v[3] == ':')) {
1324           rv = NS_ERROR_FAILURE;
1325         }
1326       } else if (nsGkAtoms::cdgroup_ == aLocalName ||
1327                  nsGkAtoms::altimg_ == aLocalName ||
1328                  nsGkAtoms::definitionURL_ == aLocalName) {
1329         // Gecko doesn't fetch these now and shouldn't in the future, but
1330         // in case someone goofs with these in the future, let's drop them.
1331         rv = NS_ERROR_FAILURE;
1332       } else {
1333         rv = secMan->CheckLoadURIWithPrincipal(sNullPrincipal, attrURI, flags,
1334                                                0);
1335       }
1336     } else {
1337       rv = secMan->CheckLoadURIWithPrincipal(sNullPrincipal, attrURI, flags, 0);
1338     }
1339   }
1340   if (NS_FAILED(rv)) {
1341     aElement->UnsetAttr(aNamespace, aLocalName, false);
1342     if (mLogRemovals) {
1343       LogMessage("Removed unsafe URI from element attribute.",
1344                  aElement->OwnerDoc(), aElement, aLocalName);
1345     }
1346     return true;
1347   }
1348   return false;
1349 }
1350 
Sanitize(DocumentFragment * aFragment)1351 void nsTreeSanitizer::Sanitize(DocumentFragment* aFragment) {
1352   // If you want to relax these preconditions, be sure to check the code in
1353   // here that notifies / does not notify or that fires mutation events if
1354   // in tree.
1355   MOZ_ASSERT(!aFragment->IsInUncomposedDoc(), "The fragment is in doc?");
1356 
1357   mFullDocument = false;
1358   SanitizeChildren(aFragment);
1359 }
1360 
Sanitize(Document * aDocument)1361 void nsTreeSanitizer::Sanitize(Document* aDocument) {
1362   // If you want to relax these preconditions, be sure to check the code in
1363   // here that notifies / does not notify or that fires mutation events if
1364   // in tree.
1365 #ifdef DEBUG
1366   MOZ_ASSERT(!aDocument->GetContainer(), "The document is in a shell.");
1367   RefPtr<mozilla::dom::Element> root = aDocument->GetRootElement();
1368   MOZ_ASSERT(root->IsHTMLElement(nsGkAtoms::html), "Not HTML root.");
1369 #endif
1370 
1371   mFullDocument = true;
1372   SanitizeChildren(aDocument);
1373 }
1374 
SanitizeChildren(nsINode * aRoot)1375 void nsTreeSanitizer::SanitizeChildren(nsINode* aRoot) {
1376   nsIContent* node = aRoot->GetFirstChild();
1377   while (node) {
1378     if (node->IsElement()) {
1379       mozilla::dom::Element* elt = node->AsElement();
1380       mozilla::dom::NodeInfo* nodeInfo = node->NodeInfo();
1381       nsAtom* localName = nodeInfo->NameAtom();
1382       int32_t ns = nodeInfo->NamespaceID();
1383 
1384       if (!mOnlyConditionalCSS && MustPrune(ns, localName, elt)) {
1385         if (mLogRemovals) {
1386           LogMessage("Removing unsafe node.", elt->OwnerDoc(), elt);
1387         }
1388         RemoveAllAttributes(elt);
1389         nsIContent* descendant = node;
1390         while ((descendant = descendant->GetNextNode(node))) {
1391           if (descendant->IsElement()) {
1392             RemoveAllAttributes(descendant->AsElement());
1393           }
1394         }
1395         nsIContent* next = node->GetNextNonChildNode(aRoot);
1396         node->RemoveFromParent();
1397         node = next;
1398         continue;
1399       }
1400       if (auto* templateEl = HTMLTemplateElement::FromNode(elt)) {
1401         // traverse into the DocFragment content attribute of template elements
1402         bool wasFullDocument = mFullDocument;
1403         mFullDocument = false;
1404         RefPtr<DocumentFragment> frag = templateEl->Content();
1405         SanitizeChildren(frag);
1406         mFullDocument = wasFullDocument;
1407       }
1408       if (nsGkAtoms::style == localName) {
1409         // If !mOnlyConditionalCSS check the following condition:
1410         // If styles aren't allowed, style elements got pruned above. Even
1411         // if styles are allowed, non-HTML, non-SVG style elements got pruned
1412         // above.
1413         NS_ASSERTION((ns == kNameSpaceID_XHTML || ns == kNameSpaceID_SVG) ||
1414                          mOnlyConditionalCSS,
1415                      "Should have only HTML or SVG here!");
1416         nsAutoString styleText;
1417         nsContentUtils::GetNodeTextContent(node, false, styleText);
1418 
1419         nsAutoString sanitizedStyle;
1420         SanitizeStyleSheet(styleText, sanitizedStyle, aRoot->OwnerDoc(),
1421                            node->GetBaseURI());
1422         RemoveAllAttributesFromDescendants(elt);
1423         nsContentUtils::SetNodeTextContent(node, sanitizedStyle, true);
1424 
1425         if (!mOnlyConditionalCSS) {
1426           AllowedAttributes allowed;
1427           allowed.mStyle = mAllowStyles;
1428           if (ns == kNameSpaceID_XHTML) {
1429             allowed.mNames = sAttributesHTML;
1430             allowed.mURLs = kURLAttributesHTML;
1431             SanitizeAttributes(elt, allowed);
1432           } else {
1433             allowed.mNames = sAttributesSVG;
1434             allowed.mURLs = kURLAttributesSVG;
1435             allowed.mXLink = true;
1436             SanitizeAttributes(elt, allowed);
1437           }
1438         }
1439         node = node->GetNextNonChildNode(aRoot);
1440         continue;
1441       }
1442       if (!mOnlyConditionalCSS && MustFlatten(ns, localName)) {
1443         if (mLogRemovals) {
1444           LogMessage("Flattening unsafe node (descendants are preserved).",
1445                      elt->OwnerDoc(), elt);
1446         }
1447         RemoveAllAttributes(elt);
1448         nsCOMPtr<nsIContent> next = node->GetNextNode(aRoot);
1449         nsCOMPtr<nsIContent> parent = node->GetParent();
1450         nsCOMPtr<nsIContent> child;  // Must keep the child alive during move
1451         ErrorResult rv;
1452         while ((child = node->GetFirstChild())) {
1453           nsCOMPtr<nsINode> refNode = node;
1454           parent->InsertBefore(*child, refNode, rv);
1455           if (rv.Failed()) {
1456             break;
1457           }
1458         }
1459         node->RemoveFromParent();
1460         node = next;
1461         continue;
1462       }
1463       if (!mOnlyConditionalCSS) {
1464         NS_ASSERTION(ns == kNameSpaceID_XHTML || ns == kNameSpaceID_SVG ||
1465                          ns == kNameSpaceID_MathML,
1466                      "Should have only HTML, MathML or SVG here!");
1467         AllowedAttributes allowed;
1468         if (ns == kNameSpaceID_XHTML) {
1469           allowed.mNames = sAttributesHTML;
1470           allowed.mURLs = kURLAttributesHTML;
1471           allowed.mStyle = mAllowStyles;
1472           allowed.mDangerousSrc =
1473               nsGkAtoms::img == localName && !mCidEmbedsOnly;
1474           SanitizeAttributes(elt, allowed);
1475         } else if (ns == kNameSpaceID_SVG) {
1476           allowed.mNames = sAttributesSVG;
1477           allowed.mURLs = kURLAttributesSVG;
1478           allowed.mXLink = true;
1479           allowed.mStyle = mAllowStyles;
1480           SanitizeAttributes(elt, allowed);
1481         } else {
1482           allowed.mNames = sAttributesMathML;
1483           allowed.mURLs = kURLAttributesMathML;
1484           allowed.mXLink = true;
1485           SanitizeAttributes(elt, allowed);
1486         }
1487       }
1488       node = node->GetNextNode(aRoot);
1489       continue;
1490     }
1491     NS_ASSERTION(!node->GetFirstChild(), "How come non-element node had kids?");
1492     nsIContent* next = node->GetNextNonChildNode(aRoot);
1493     if (!mOnlyConditionalCSS && (!mAllowComments && node->IsComment())) {
1494       node->RemoveFromParent();
1495     }
1496     node = next;
1497   }
1498 }
1499 
RemoveAllAttributes(Element * aElement)1500 void nsTreeSanitizer::RemoveAllAttributes(Element* aElement) {
1501   const nsAttrName* attrName;
1502   while ((attrName = aElement->GetAttrNameAt(0))) {
1503     int32_t attrNs = attrName->NamespaceID();
1504     RefPtr<nsAtom> attrLocal = attrName->LocalName();
1505     aElement->UnsetAttr(attrNs, attrLocal, false);
1506   }
1507 }
1508 
RemoveAllAttributesFromDescendants(mozilla::dom::Element * aElement)1509 void nsTreeSanitizer::RemoveAllAttributesFromDescendants(
1510     mozilla::dom::Element* aElement) {
1511   nsIContent* node = aElement->GetFirstChild();
1512   while (node) {
1513     if (node->IsElement()) {
1514       mozilla::dom::Element* elt = node->AsElement();
1515       RemoveAllAttributes(elt);
1516     }
1517     node = node->GetNextNode(aElement);
1518   }
1519 }
1520 
LogMessage(const char * aMessage,Document * aDoc,Element * aElement,nsAtom * aAttr)1521 void nsTreeSanitizer::LogMessage(const char* aMessage, Document* aDoc,
1522                                  Element* aElement, nsAtom* aAttr) {
1523   if (mLogRemovals) {
1524     nsAutoString msg;
1525     msg.Assign(NS_ConvertASCIItoUTF16(aMessage));
1526     if (aElement) {
1527       msg.Append(u" Element: "_ns + aElement->LocalName() + u"."_ns);
1528     }
1529     if (aAttr) {
1530       msg.Append(u" Attribute: "_ns + nsDependentAtomString(aAttr) + u"."_ns);
1531     }
1532 
1533     nsContentUtils::ReportToConsoleNonLocalized(
1534         msg, nsIScriptError::warningFlag, "DOM"_ns, aDoc);
1535   }
1536 }
1537 
InitializeStatics()1538 void nsTreeSanitizer::InitializeStatics() {
1539   MOZ_ASSERT(!sElementsHTML, "Initializing a second time.");
1540 
1541   sElementsHTML = new AtomsTable(ArrayLength(kElementsHTML));
1542   for (uint32_t i = 0; kElementsHTML[i]; i++) {
1543     sElementsHTML->Insert(kElementsHTML[i]);
1544   }
1545 
1546   sAttributesHTML = new AtomsTable(ArrayLength(kAttributesHTML));
1547   for (uint32_t i = 0; kAttributesHTML[i]; i++) {
1548     sAttributesHTML->Insert(kAttributesHTML[i]);
1549   }
1550 
1551   sPresAttributesHTML = new AtomsTable(ArrayLength(kPresAttributesHTML));
1552   for (uint32_t i = 0; kPresAttributesHTML[i]; i++) {
1553     sPresAttributesHTML->Insert(kPresAttributesHTML[i]);
1554   }
1555 
1556   sElementsSVG = new AtomsTable(ArrayLength(kElementsSVG));
1557   for (uint32_t i = 0; kElementsSVG[i]; i++) {
1558     sElementsSVG->Insert(kElementsSVG[i]);
1559   }
1560 
1561   sAttributesSVG = new AtomsTable(ArrayLength(kAttributesSVG));
1562   for (uint32_t i = 0; kAttributesSVG[i]; i++) {
1563     sAttributesSVG->Insert(kAttributesSVG[i]);
1564   }
1565 
1566   sElementsMathML = new AtomsTable(ArrayLength(kElementsMathML));
1567   for (uint32_t i = 0; kElementsMathML[i]; i++) {
1568     sElementsMathML->Insert(kElementsMathML[i]);
1569   }
1570 
1571   sAttributesMathML = new AtomsTable(ArrayLength(kAttributesMathML));
1572   for (uint32_t i = 0; kAttributesMathML[i]; i++) {
1573     sAttributesMathML->Insert(kAttributesMathML[i]);
1574   }
1575 
1576   nsCOMPtr<nsIPrincipal> principal =
1577       NullPrincipal::CreateWithoutOriginAttributes();
1578   principal.forget(&sNullPrincipal);
1579 }
1580 
ReleaseStatics()1581 void nsTreeSanitizer::ReleaseStatics() {
1582   delete sElementsHTML;
1583   sElementsHTML = nullptr;
1584 
1585   delete sAttributesHTML;
1586   sAttributesHTML = nullptr;
1587 
1588   delete sPresAttributesHTML;
1589   sPresAttributesHTML = nullptr;
1590 
1591   delete sElementsSVG;
1592   sElementsSVG = nullptr;
1593 
1594   delete sAttributesSVG;
1595   sAttributesSVG = nullptr;
1596 
1597   delete sElementsMathML;
1598   sElementsMathML = nullptr;
1599 
1600   delete sAttributesMathML;
1601   sAttributesMathML = nullptr;
1602 
1603   NS_IF_RELEASE(sNullPrincipal);
1604 }
1605 
WithWebSanitizerOptions(const mozilla::dom::SanitizerConfig & aOptions)1606 void nsTreeSanitizer::WithWebSanitizerOptions(
1607     const mozilla::dom::SanitizerConfig& aOptions) {
1608   if (!aOptions.IsAnyMemberPresent()) {
1609     return;
1610   }
1611   if (aOptions.mAllowComments.WasPassed()) {
1612     mAllowComments = aOptions.mAllowComments.Value();
1613   }
1614   if (aOptions.mAllowElements.WasPassed()) {
1615     mIsCustomized = true;
1616     const Sequence<nsString>& allowedElements = aOptions.mAllowElements.Value();
1617     mAllowedElements = MakeUnique<DynamicAtomsTable>(allowedElements.Length());
1618     for (const nsString& elem : allowedElements) {
1619       nsAutoString lowercaseElem;
1620       nsContentUtils::ASCIIToLower(elem, lowercaseElem);
1621       RefPtr<nsAtom> elAsAtom = NS_Atomize(lowercaseElem);
1622       mAllowedElements->Insert(elAsAtom);
1623     }
1624   } else {
1625     mAllowedElements = nullptr;
1626   }
1627   if (aOptions.mBlockElements.WasPassed()) {
1628     mIsCustomized = true;
1629     const Sequence<nsString>& blockedElements = aOptions.mBlockElements.Value();
1630     mBlockedElements = MakeUnique<DynamicAtomsTable>(blockedElements.Length());
1631     for (const nsString& elem : blockedElements) {
1632       nsAutoString lowercaseElem;
1633       nsContentUtils::ASCIIToLower(elem, lowercaseElem);
1634       RefPtr<nsAtom> elAsAtom = NS_Atomize(lowercaseElem);
1635       mBlockedElements->Insert(elAsAtom);
1636     }
1637   } else {
1638     mBlockedElements = nullptr;
1639   }
1640   if (aOptions.mAllowAttributes.WasPassed()) {
1641     mIsCustomized = true;
1642     const Record<nsString, Sequence<nsString>>& allowedAttributes =
1643         aOptions.mAllowAttributes.Value();
1644     mAllowedAttributes = MakeUnique<
1645         nsTHashMap<RefPtr<nsAtom>, mozilla::UniquePtr<DynamicAtomsTable>>>();
1646     nsAutoString name;
1647     for (const auto& entries : allowedAttributes.Entries()) {
1648       UniquePtr<DynamicAtomsTable> elems =
1649           MakeUnique<DynamicAtomsTable>(allowedAttributes.Entries().Length());
1650       for (const auto& elem : entries.mValue) {
1651         nsAutoString lowercaseElem;
1652         nsContentUtils::ASCIIToLower(elem, lowercaseElem);
1653         RefPtr<nsAtom> elAsAtom = NS_Atomize(lowercaseElem);
1654         elems->Insert(elAsAtom);
1655       }
1656       nsAutoString attrName;
1657       nsContentUtils::ASCIIToLower(entries.mKey, attrName);
1658       RefPtr<nsAtom> attrAtom = NS_Atomize(attrName);
1659       mAllowedAttributes->InsertOrUpdate(attrAtom, std::move(elems));
1660     }
1661   } else {
1662     mAllowedAttributes = nullptr;
1663   }
1664   if (aOptions.mDropAttributes.WasPassed()) {
1665     mIsCustomized = true;
1666     const Record<nsString, Sequence<nsString>>& droppedAttributes =
1667         aOptions.mDropAttributes.Value();
1668     mDroppedAttributes = MakeUnique<
1669         nsTHashMap<RefPtr<nsAtom>, mozilla::UniquePtr<DynamicAtomsTable>>>();
1670     nsAutoString name;
1671     for (const auto& entries : droppedAttributes.Entries()) {
1672       UniquePtr<DynamicAtomsTable> elems =
1673           MakeUnique<DynamicAtomsTable>(droppedAttributes.Entries().Length());
1674       for (const auto& elem : entries.mValue) {
1675         nsAutoString lowercaseElem;
1676         nsContentUtils::ASCIIToLower(elem, lowercaseElem);
1677         RefPtr<nsAtom> elAsAtom = NS_Atomize(lowercaseElem);
1678         elems->Insert(elAsAtom);
1679       }
1680       nsAutoString attrName;
1681       nsContentUtils::ASCIIToLower(entries.mKey, attrName);
1682       RefPtr<nsAtom> attrAtom = NS_Atomize(attrName);
1683       mDroppedAttributes->InsertOrUpdate(attrAtom, std::move(elems));
1684     }
1685   } else {
1686     mDroppedAttributes = nullptr;
1687   }
1688   // TODO(freddy) Add handling of other keys in SanitizerConfig
1689 }
1690