nsTreeSanitizer.cpp (58896B)
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 <iterator> 10 11 #include "NonCustomCSSPropertyId.h" 12 #include "mozilla/Algorithm.h" 13 #include "mozilla/DeclarationBlock.h" 14 #include "mozilla/NullPrincipal.h" 15 #include "mozilla/StaticPrefs_dom.h" 16 #include "mozilla/StyleSheetInlines.h" 17 #include "mozilla/dom/Document.h" 18 #include "mozilla/dom/DocumentFragment.h" 19 #include "mozilla/dom/HTMLFormElement.h" 20 #include "mozilla/dom/HTMLTemplateElement.h" 21 #include "mozilla/dom/HTMLUnknownElement.h" 22 #include "mozilla/dom/Link.h" 23 #include "mozilla/dom/SRIMetadata.h" 24 #include "mozilla/dom/SanitizerBinding.h" 25 #include "mozilla/dom/ShadowIncludingTreeIterator.h" 26 #include "nsAtom.h" 27 #include "nsAttrName.h" 28 #include "nsComponentManagerUtils.h" 29 #include "nsContentUtils.h" 30 #include "nsHashtablesFwd.h" 31 #include "nsIParserUtils.h" 32 #include "nsIScriptError.h" 33 #include "nsIScriptSecurityManager.h" 34 #include "nsNameSpaceManager.h" 35 #include "nsNetUtil.h" 36 #include "nsQueryObject.h" 37 #include "nsString.h" 38 #include "nsTHashtable.h" 39 #include "nsUnicharInputStream.h" 40 41 using namespace mozilla; 42 using namespace mozilla::dom; 43 44 // 45 // Thanks to Mark Pilgrim and Sam Ruby for the initial whitelist 46 // 47 const nsStaticAtom* const kElementsHTML[] = { 48 // clang-format off 49 nsGkAtoms::a, 50 nsGkAtoms::abbr, 51 nsGkAtoms::acronym, 52 nsGkAtoms::address, 53 nsGkAtoms::area, 54 nsGkAtoms::article, 55 nsGkAtoms::aside, 56 nsGkAtoms::audio, 57 nsGkAtoms::b, 58 nsGkAtoms::bdi, 59 nsGkAtoms::bdo, 60 nsGkAtoms::big, 61 nsGkAtoms::blockquote, 62 // body checked specially 63 nsGkAtoms::br, 64 nsGkAtoms::button, 65 nsGkAtoms::canvas, 66 nsGkAtoms::caption, 67 nsGkAtoms::center, 68 nsGkAtoms::cite, 69 nsGkAtoms::code, 70 nsGkAtoms::col, 71 nsGkAtoms::colgroup, 72 nsGkAtoms::data, 73 nsGkAtoms::datalist, 74 nsGkAtoms::dd, 75 nsGkAtoms::del, 76 nsGkAtoms::details, 77 nsGkAtoms::dfn, 78 nsGkAtoms::dialog, 79 nsGkAtoms::dir, 80 nsGkAtoms::div, 81 nsGkAtoms::dl, 82 nsGkAtoms::dt, 83 nsGkAtoms::em, 84 nsGkAtoms::fieldset, 85 nsGkAtoms::figcaption, 86 nsGkAtoms::figure, 87 nsGkAtoms::font, 88 nsGkAtoms::footer, 89 nsGkAtoms::form, 90 nsGkAtoms::h1, 91 nsGkAtoms::h2, 92 nsGkAtoms::h3, 93 nsGkAtoms::h4, 94 nsGkAtoms::h5, 95 nsGkAtoms::h6, 96 // head checked specially 97 nsGkAtoms::header, 98 nsGkAtoms::hgroup, 99 nsGkAtoms::hr, 100 // html checked specially 101 nsGkAtoms::i, 102 nsGkAtoms::img, 103 nsGkAtoms::input, 104 nsGkAtoms::ins, 105 nsGkAtoms::kbd, 106 nsGkAtoms::keygen, 107 nsGkAtoms::label, 108 nsGkAtoms::legend, 109 nsGkAtoms::li, 110 nsGkAtoms::link, 111 nsGkAtoms::listing, 112 nsGkAtoms::main, 113 nsGkAtoms::map, 114 nsGkAtoms::mark, 115 nsGkAtoms::menu, 116 nsGkAtoms::meta, 117 nsGkAtoms::meter, 118 nsGkAtoms::nav, 119 nsGkAtoms::nobr, 120 nsGkAtoms::noscript, 121 nsGkAtoms::ol, 122 nsGkAtoms::optgroup, 123 nsGkAtoms::option, 124 nsGkAtoms::output, 125 nsGkAtoms::p, 126 nsGkAtoms::picture, 127 nsGkAtoms::pre, 128 nsGkAtoms::progress, 129 nsGkAtoms::q, 130 nsGkAtoms::rb, 131 nsGkAtoms::rp, 132 nsGkAtoms::rt, 133 nsGkAtoms::rtc, 134 nsGkAtoms::ruby, 135 nsGkAtoms::s, 136 nsGkAtoms::samp, 137 nsGkAtoms::section, 138 nsGkAtoms::select, 139 nsGkAtoms::small, 140 nsGkAtoms::source, 141 nsGkAtoms::span, 142 nsGkAtoms::strike, 143 nsGkAtoms::strong, 144 nsGkAtoms::sub, 145 nsGkAtoms::summary, 146 nsGkAtoms::sup, 147 // style checked specially 148 nsGkAtoms::table, 149 nsGkAtoms::tbody, 150 nsGkAtoms::td, 151 // template checked and traversed specially 152 nsGkAtoms::textarea, 153 nsGkAtoms::tfoot, 154 nsGkAtoms::th, 155 nsGkAtoms::thead, 156 nsGkAtoms::time, 157 // title checked specially 158 nsGkAtoms::tr, 159 nsGkAtoms::track, 160 nsGkAtoms::tt, 161 nsGkAtoms::u, 162 nsGkAtoms::ul, 163 nsGkAtoms::var, 164 nsGkAtoms::video, 165 nsGkAtoms::wbr, 166 nullptr 167 // clang-format on 168 }; 169 170 const nsStaticAtom* const kAttributesHTML[] = { 171 // clang-format off 172 nsGkAtoms::abbr, 173 nsGkAtoms::accept, 174 nsGkAtoms::acceptcharset, 175 nsGkAtoms::accesskey, 176 nsGkAtoms::action, 177 nsGkAtoms::alt, 178 nsGkAtoms::as, 179 nsGkAtoms::autocomplete, 180 nsGkAtoms::autofocus, 181 nsGkAtoms::autoplay, 182 nsGkAtoms::axis, 183 nsGkAtoms::_char, 184 nsGkAtoms::charoff, 185 nsGkAtoms::charset, 186 nsGkAtoms::checked, 187 nsGkAtoms::cite, 188 nsGkAtoms::_class, 189 nsGkAtoms::cols, 190 nsGkAtoms::colspan, 191 nsGkAtoms::content, 192 nsGkAtoms::contenteditable, 193 nsGkAtoms::contextmenu, 194 nsGkAtoms::controls, 195 nsGkAtoms::coords, 196 nsGkAtoms::crossorigin, 197 nsGkAtoms::datetime, 198 nsGkAtoms::dir, 199 nsGkAtoms::disabled, 200 nsGkAtoms::draggable, 201 nsGkAtoms::enctype, 202 nsGkAtoms::face, 203 nsGkAtoms::_for, 204 nsGkAtoms::frame, 205 nsGkAtoms::headers, 206 nsGkAtoms::height, 207 nsGkAtoms::hidden, 208 nsGkAtoms::high, 209 nsGkAtoms::href, 210 nsGkAtoms::hreflang, 211 nsGkAtoms::icon, 212 nsGkAtoms::id, 213 nsGkAtoms::integrity, 214 nsGkAtoms::ismap, 215 nsGkAtoms::itemid, 216 nsGkAtoms::itemprop, 217 nsGkAtoms::itemref, 218 nsGkAtoms::itemscope, 219 nsGkAtoms::itemtype, 220 nsGkAtoms::kind, 221 nsGkAtoms::label, 222 nsGkAtoms::lang, 223 nsGkAtoms::list, 224 nsGkAtoms::longdesc, 225 nsGkAtoms::loop, 226 nsGkAtoms::low, 227 nsGkAtoms::max, 228 nsGkAtoms::maxlength, 229 nsGkAtoms::media, 230 nsGkAtoms::method, 231 nsGkAtoms::min, 232 nsGkAtoms::minlength, 233 nsGkAtoms::multiple, 234 nsGkAtoms::muted, 235 nsGkAtoms::name, 236 nsGkAtoms::nohref, 237 nsGkAtoms::novalidate, 238 nsGkAtoms::nowrap, 239 nsGkAtoms::open, 240 nsGkAtoms::optimum, 241 nsGkAtoms::pattern, 242 nsGkAtoms::placeholder, 243 nsGkAtoms::playbackrate, 244 nsGkAtoms::poster, 245 nsGkAtoms::preload, 246 nsGkAtoms::prompt, 247 nsGkAtoms::pubdate, 248 nsGkAtoms::radiogroup, 249 nsGkAtoms::readonly, 250 nsGkAtoms::rel, 251 nsGkAtoms::required, 252 nsGkAtoms::rev, 253 nsGkAtoms::reversed, 254 nsGkAtoms::role, 255 nsGkAtoms::rows, 256 nsGkAtoms::rowspan, 257 nsGkAtoms::rules, 258 nsGkAtoms::scoped, 259 nsGkAtoms::scope, 260 nsGkAtoms::selected, 261 nsGkAtoms::shape, 262 nsGkAtoms::span, 263 nsGkAtoms::spellcheck, 264 nsGkAtoms::src, 265 nsGkAtoms::srclang, 266 nsGkAtoms::start, 267 nsGkAtoms::summary, 268 nsGkAtoms::tabindex, 269 nsGkAtoms::target, 270 nsGkAtoms::title, 271 nsGkAtoms::type, 272 nsGkAtoms::usemap, 273 nsGkAtoms::value, 274 nsGkAtoms::width, 275 nsGkAtoms::wrap, 276 nullptr 277 // clang-format on 278 }; 279 280 const nsStaticAtom* const kPresAttributesHTML[] = { 281 // clang-format off 282 nsGkAtoms::align, 283 nsGkAtoms::background, 284 nsGkAtoms::bgcolor, 285 nsGkAtoms::border, 286 nsGkAtoms::cellpadding, 287 nsGkAtoms::cellspacing, 288 nsGkAtoms::color, 289 nsGkAtoms::compact, 290 nsGkAtoms::clear, 291 nsGkAtoms::hspace, 292 nsGkAtoms::noshade, 293 nsGkAtoms::pointSize, 294 nsGkAtoms::size, 295 nsGkAtoms::valign, 296 nsGkAtoms::vspace, 297 nullptr 298 // clang-format on 299 }; 300 301 // List of HTML attributes with URLs that the 302 // browser will fetch. Should be kept in sync with 303 // https://html.spec.whatwg.org/multipage/indices.html#attributes-3 304 const nsStaticAtom* const kURLAttributesHTML[] = { 305 // clang-format off 306 nsGkAtoms::action, 307 nsGkAtoms::href, 308 nsGkAtoms::src, 309 nsGkAtoms::longdesc, 310 nsGkAtoms::cite, 311 nsGkAtoms::background, 312 nsGkAtoms::formaction, 313 nsGkAtoms::data, 314 nsGkAtoms::ping, 315 nsGkAtoms::poster, 316 nullptr 317 // clang-format on 318 }; 319 320 const nsStaticAtom* const kElementsSVG[] = { 321 nsGkAtoms::a, // a 322 nsGkAtoms::circle, // circle 323 nsGkAtoms::clipPath, // clipPath 324 nsGkAtoms::color_profile, // color-profile 325 nsGkAtoms::cursor, // cursor 326 nsGkAtoms::defs, // defs 327 nsGkAtoms::desc, // desc 328 nsGkAtoms::ellipse, // ellipse 329 nsGkAtoms::elevation, // elevation 330 nsGkAtoms::erode, // erode 331 nsGkAtoms::ex, // ex 332 nsGkAtoms::exact, // exact 333 nsGkAtoms::exponent, // exponent 334 nsGkAtoms::feBlend, // feBlend 335 nsGkAtoms::feColorMatrix, // feColorMatrix 336 nsGkAtoms::feComponentTransfer, // feComponentTransfer 337 nsGkAtoms::feComposite, // feComposite 338 nsGkAtoms::feConvolveMatrix, // feConvolveMatrix 339 nsGkAtoms::feDiffuseLighting, // feDiffuseLighting 340 nsGkAtoms::feDisplacementMap, // feDisplacementMap 341 nsGkAtoms::feDistantLight, // feDistantLight 342 nsGkAtoms::feDropShadow, // feDropShadow 343 nsGkAtoms::feFlood, // feFlood 344 nsGkAtoms::feFuncA, // feFuncA 345 nsGkAtoms::feFuncB, // feFuncB 346 nsGkAtoms::feFuncG, // feFuncG 347 nsGkAtoms::feFuncR, // feFuncR 348 nsGkAtoms::feGaussianBlur, // feGaussianBlur 349 nsGkAtoms::feImage, // feImage 350 nsGkAtoms::feMerge, // feMerge 351 nsGkAtoms::feMergeNode, // feMergeNode 352 nsGkAtoms::feMorphology, // feMorphology 353 nsGkAtoms::feOffset, // feOffset 354 nsGkAtoms::fePointLight, // fePointLight 355 nsGkAtoms::feSpecularLighting, // feSpecularLighting 356 nsGkAtoms::feSpotLight, // feSpotLight 357 nsGkAtoms::feTile, // feTile 358 nsGkAtoms::feTurbulence, // feTurbulence 359 nsGkAtoms::filter, // filter 360 nsGkAtoms::font, // font 361 nsGkAtoms::font_face, // font-face 362 nsGkAtoms::font_face_format, // font-face-format 363 nsGkAtoms::font_face_name, // font-face-name 364 nsGkAtoms::font_face_src, // font-face-src 365 nsGkAtoms::font_face_uri, // font-face-uri 366 nsGkAtoms::foreignObject, // foreignObject 367 nsGkAtoms::g, // g 368 // glyph 369 nsGkAtoms::glyphRef, // glyphRef 370 // hkern 371 nsGkAtoms::image, // image 372 nsGkAtoms::line, // line 373 nsGkAtoms::linearGradient, // linearGradient 374 nsGkAtoms::marker, // marker 375 nsGkAtoms::mask, // mask 376 nsGkAtoms::metadata, // metadata 377 nsGkAtoms::missingGlyph, // missingGlyph 378 nsGkAtoms::mpath, // mpath 379 nsGkAtoms::path, // path 380 nsGkAtoms::pattern, // pattern 381 nsGkAtoms::polygon, // polygon 382 nsGkAtoms::polyline, // polyline 383 nsGkAtoms::radialGradient, // radialGradient 384 nsGkAtoms::rect, // rect 385 nsGkAtoms::stop, // stop 386 nsGkAtoms::svg, // svg 387 nsGkAtoms::svgSwitch, // switch 388 nsGkAtoms::symbol, // symbol 389 nsGkAtoms::text, // text 390 nsGkAtoms::textPath, // textPath 391 nsGkAtoms::title, // title 392 nsGkAtoms::tref, // tref 393 nsGkAtoms::tspan, // tspan 394 nsGkAtoms::use, // use 395 nsGkAtoms::view, // view 396 // vkern 397 nullptr}; 398 399 constexpr const nsStaticAtom* const kAttributesSVG[] = { 400 // accent-height 401 nsGkAtoms::accumulate, // accumulate 402 nsGkAtoms::additive, // additive 403 nsGkAtoms::alignment_baseline, // alignment-baseline 404 // alphabetic 405 nsGkAtoms::amplitude, // amplitude 406 // arabic-form 407 // ascent 408 nsGkAtoms::attributeName, // attributeName 409 nsGkAtoms::attributeType, // attributeType 410 nsGkAtoms::azimuth, // azimuth 411 nsGkAtoms::baseFrequency, // baseFrequency 412 nsGkAtoms::baseline_shift, // baseline-shift 413 // baseProfile 414 // bbox 415 nsGkAtoms::begin, // begin 416 nsGkAtoms::bias, // bias 417 nsGkAtoms::by, // by 418 nsGkAtoms::calcMode, // calcMode 419 // cap-height 420 nsGkAtoms::_class, // class 421 nsGkAtoms::clip_path, // clip-path 422 nsGkAtoms::clip_rule, // clip-rule 423 nsGkAtoms::clipPathUnits, // clipPathUnits 424 nsGkAtoms::color, // color 425 nsGkAtoms::color_interpolation, // color-interpolation 426 nsGkAtoms::color_interpolation_filters, // color-interpolation-filters 427 nsGkAtoms::cursor, // cursor 428 nsGkAtoms::cx, // cx 429 nsGkAtoms::cy, // cy 430 nsGkAtoms::d, // d 431 // descent 432 nsGkAtoms::diffuseConstant, // diffuseConstant 433 nsGkAtoms::direction, // direction 434 nsGkAtoms::display, // display 435 nsGkAtoms::divisor, // divisor 436 nsGkAtoms::dominant_baseline, // dominant-baseline 437 nsGkAtoms::dur, // dur 438 nsGkAtoms::dx, // dx 439 nsGkAtoms::dy, // dy 440 nsGkAtoms::edgeMode, // edgeMode 441 nsGkAtoms::elevation, // elevation 442 // enable-background 443 nsGkAtoms::end, // end 444 nsGkAtoms::fill, // fill 445 nsGkAtoms::fill_opacity, // fill-opacity 446 nsGkAtoms::fill_rule, // fill-rule 447 nsGkAtoms::filter, // filter 448 nsGkAtoms::filterUnits, // filterUnits 449 nsGkAtoms::flood_color, // flood-color 450 nsGkAtoms::flood_opacity, // flood-opacity 451 // XXX focusable 452 nsGkAtoms::font, // font 453 nsGkAtoms::font_family, // font-family 454 nsGkAtoms::font_size, // font-size 455 nsGkAtoms::font_size_adjust, // font-size-adjust 456 nsGkAtoms::font_stretch, // font-stretch 457 nsGkAtoms::font_style, // font-style 458 nsGkAtoms::font_variant, // font-variant 459 nsGkAtoms::font_weight, // font-weight 460 nsGkAtoms::format, // format 461 nsGkAtoms::from, // from 462 nsGkAtoms::fx, // fx 463 nsGkAtoms::fy, // fy 464 // g1 465 // g2 466 // glyph-name 467 // glyphRef 468 // glyph-orientation-horizontal 469 // glyph-orientation-vertical 470 nsGkAtoms::gradientTransform, // gradientTransform 471 nsGkAtoms::gradientUnits, // gradientUnits 472 nsGkAtoms::height, // height 473 nsGkAtoms::href, 474 // horiz-adv-x 475 // horiz-origin-x 476 // horiz-origin-y 477 nsGkAtoms::id, // id 478 // ideographic 479 nsGkAtoms::image_rendering, // image-rendering 480 nsGkAtoms::in, // in 481 nsGkAtoms::in2, // in2 482 nsGkAtoms::intercept, // intercept 483 // k 484 nsGkAtoms::k1, // k1 485 nsGkAtoms::k2, // k2 486 nsGkAtoms::k3, // k3 487 nsGkAtoms::k4, // k4 488 // kerning 489 nsGkAtoms::kernelMatrix, // kernelMatrix 490 nsGkAtoms::kernelUnitLength, // kernelUnitLength 491 nsGkAtoms::keyPoints, // keyPoints 492 nsGkAtoms::keySplines, // keySplines 493 nsGkAtoms::keyTimes, // keyTimes 494 nsGkAtoms::lang, // lang 495 // lengthAdjust 496 nsGkAtoms::letter_spacing, // letter-spacing 497 nsGkAtoms::lighting_color, // lighting-color 498 nsGkAtoms::limitingConeAngle, // limitingConeAngle 499 // local 500 nsGkAtoms::marker, // marker 501 nsGkAtoms::marker_end, // marker-end 502 nsGkAtoms::marker_mid, // marker-mid 503 nsGkAtoms::marker_start, // marker-start 504 nsGkAtoms::markerHeight, // markerHeight 505 nsGkAtoms::markerUnits, // markerUnits 506 nsGkAtoms::markerWidth, // markerWidth 507 nsGkAtoms::mask, // mask 508 nsGkAtoms::maskContentUnits, // maskContentUnits 509 nsGkAtoms::maskUnits, // maskUnits 510 // mathematical 511 nsGkAtoms::max, // max 512 nsGkAtoms::media, // media 513 nsGkAtoms::method, // method 514 nsGkAtoms::min, // min 515 nsGkAtoms::mode, // mode 516 nsGkAtoms::name, // name 517 nsGkAtoms::numOctaves, // numOctaves 518 nsGkAtoms::offset, // offset 519 nsGkAtoms::opacity, // opacity 520 nsGkAtoms::_operator, // operator 521 nsGkAtoms::order, // order 522 nsGkAtoms::orient, // orient 523 nsGkAtoms::orientation, // orientation 524 // origin 525 // overline-position 526 // overline-thickness 527 nsGkAtoms::overflow, // overflow 528 // panose-1 529 nsGkAtoms::path, // path 530 nsGkAtoms::pathLength, // pathLength 531 nsGkAtoms::patternContentUnits, // patternContentUnits 532 nsGkAtoms::patternTransform, // patternTransform 533 nsGkAtoms::patternUnits, // patternUnits 534 nsGkAtoms::pointer_events, // pointer-events XXX is this safe? 535 nsGkAtoms::points, // points 536 nsGkAtoms::pointsAtX, // pointsAtX 537 nsGkAtoms::pointsAtY, // pointsAtY 538 nsGkAtoms::pointsAtZ, // pointsAtZ 539 nsGkAtoms::preserveAlpha, // preserveAlpha 540 nsGkAtoms::preserveAspectRatio, // preserveAspectRatio 541 nsGkAtoms::primitiveUnits, // primitiveUnits 542 nsGkAtoms::r, // r 543 nsGkAtoms::radius, // radius 544 nsGkAtoms::refX, // refX 545 nsGkAtoms::refY, // refY 546 nsGkAtoms::repeatCount, // repeatCount 547 nsGkAtoms::repeatDur, // repeatDur 548 nsGkAtoms::requiredExtensions, // requiredExtensions 549 nsGkAtoms::requiredFeatures, // requiredFeatures 550 nsGkAtoms::restart, // restart 551 nsGkAtoms::result, // result 552 nsGkAtoms::rotate, // rotate 553 nsGkAtoms::rx, // rx 554 nsGkAtoms::ry, // ry 555 nsGkAtoms::scale, // scale 556 nsGkAtoms::seed, // seed 557 nsGkAtoms::shape_rendering, // shape-rendering 558 nsGkAtoms::slope, // slope 559 nsGkAtoms::spacing, // spacing 560 nsGkAtoms::specularConstant, // specularConstant 561 nsGkAtoms::specularExponent, // specularExponent 562 nsGkAtoms::spreadMethod, // spreadMethod 563 nsGkAtoms::startOffset, // startOffset 564 nsGkAtoms::stdDeviation, // stdDeviation 565 // stemh 566 // stemv 567 nsGkAtoms::stitchTiles, // stitchTiles 568 nsGkAtoms::stop_color, // stop-color 569 nsGkAtoms::stop_opacity, // stop-opacity 570 // strikethrough-position 571 // strikethrough-thickness 572 nsGkAtoms::string, // string 573 nsGkAtoms::stroke, // stroke 574 nsGkAtoms::stroke_dasharray, // stroke-dasharray 575 nsGkAtoms::stroke_dashoffset, // stroke-dashoffset 576 nsGkAtoms::stroke_linecap, // stroke-linecap 577 nsGkAtoms::stroke_linejoin, // stroke-linejoin 578 nsGkAtoms::stroke_miterlimit, // stroke-miterlimit 579 nsGkAtoms::stroke_opacity, // stroke-opacity 580 nsGkAtoms::stroke_width, // stroke-width 581 nsGkAtoms::surfaceScale, // surfaceScale 582 nsGkAtoms::systemLanguage, // systemLanguage 583 nsGkAtoms::tableValues, // tableValues 584 nsGkAtoms::target, // target 585 nsGkAtoms::targetX, // targetX 586 nsGkAtoms::targetY, // targetY 587 nsGkAtoms::text_anchor, // text-anchor 588 nsGkAtoms::text_decoration, // text-decoration 589 // textLength 590 nsGkAtoms::text_rendering, // text-rendering 591 nsGkAtoms::title, // title 592 nsGkAtoms::to, // to 593 nsGkAtoms::transform, // transform 594 nsGkAtoms::transform_origin, // transform-origin 595 nsGkAtoms::type, // type 596 // u1 597 // u2 598 // underline-position 599 // underline-thickness 600 // unicode 601 nsGkAtoms::unicode_bidi, // unicode-bidi 602 // unicode-range 603 // units-per-em 604 // v-alphabetic 605 // v-hanging 606 // v-ideographic 607 // v-mathematical 608 nsGkAtoms::values, // values 609 nsGkAtoms::vector_effect, // vector-effect 610 // vert-adv-y 611 // vert-origin-x 612 // vert-origin-y 613 nsGkAtoms::viewBox, // viewBox 614 nsGkAtoms::viewTarget, // viewTarget 615 nsGkAtoms::visibility, // visibility 616 nsGkAtoms::width, // width 617 // widths 618 nsGkAtoms::word_spacing, // word-spacing 619 nsGkAtoms::writing_mode, // writing-mode 620 nsGkAtoms::x, // x 621 // x-height 622 nsGkAtoms::x1, // x1 623 nsGkAtoms::x2, // x2 624 nsGkAtoms::xChannelSelector, // xChannelSelector 625 nsGkAtoms::y, // y 626 nsGkAtoms::y1, // y1 627 nsGkAtoms::y2, // y2 628 nsGkAtoms::yChannelSelector, // yChannelSelector 629 nsGkAtoms::z, // z 630 nsGkAtoms::zoomAndPan, // zoomAndPan 631 nullptr}; 632 633 constexpr const nsStaticAtom* const kURLAttributesSVG[] = {nsGkAtoms::href, 634 nullptr}; 635 636 static_assert(AllOf(std::begin(kURLAttributesSVG), std::end(kURLAttributesSVG), 637 [](auto aURLAttributeSVG) { 638 return AnyOf(std::begin(kAttributesSVG), 639 std::end(kAttributesSVG), 640 [&](auto aAttributeSVG) { 641 return aAttributeSVG == aURLAttributeSVG; 642 }); 643 })); 644 645 const nsStaticAtom* const kElementsMathML[] = { 646 nsGkAtoms::abs, // abs 647 nsGkAtoms::_and, // and 648 nsGkAtoms::annotation, // annotation 649 nsGkAtoms::annotation_xml, // annotation-xml 650 nsGkAtoms::apply, // apply 651 nsGkAtoms::approx, // approx 652 nsGkAtoms::arccos, // arccos 653 nsGkAtoms::arccosh, // arccosh 654 nsGkAtoms::arccot, // arccot 655 nsGkAtoms::arccoth, // arccoth 656 nsGkAtoms::arccsc, // arccsc 657 nsGkAtoms::arccsch, // arccsch 658 nsGkAtoms::arcsec, // arcsec 659 nsGkAtoms::arcsech, // arcsech 660 nsGkAtoms::arcsin, // arcsin 661 nsGkAtoms::arcsinh, // arcsinh 662 nsGkAtoms::arctan, // arctan 663 nsGkAtoms::arctanh, // arctanh 664 nsGkAtoms::arg, // arg 665 nsGkAtoms::bind, // bind 666 nsGkAtoms::bvar, // bvar 667 nsGkAtoms::card, // card 668 nsGkAtoms::cartesianproduct, // cartesianproduct 669 nsGkAtoms::cbytes, // cbytes 670 nsGkAtoms::ceiling, // ceiling 671 nsGkAtoms::cerror, // cerror 672 nsGkAtoms::ci, // ci 673 nsGkAtoms::cn, // cn 674 nsGkAtoms::codomain, // codomain 675 nsGkAtoms::complexes, // complexes 676 nsGkAtoms::compose, // compose 677 nsGkAtoms::condition, // condition 678 nsGkAtoms::conjugate, // conjugate 679 nsGkAtoms::cos, // cos 680 nsGkAtoms::cosh, // cosh 681 nsGkAtoms::cot, // cot 682 nsGkAtoms::coth, // coth 683 nsGkAtoms::cs, // cs 684 nsGkAtoms::csc, // csc 685 nsGkAtoms::csch, // csch 686 nsGkAtoms::csymbol, // csymbol 687 nsGkAtoms::curl, // curl 688 nsGkAtoms::declare, // declare 689 nsGkAtoms::degree, // degree 690 nsGkAtoms::determinant, // determinant 691 nsGkAtoms::diff, // diff 692 nsGkAtoms::divergence, // divergence 693 nsGkAtoms::divide, // divide 694 nsGkAtoms::domain, // domain 695 nsGkAtoms::domainofapplication, // domainofapplication 696 nsGkAtoms::el, // el 697 nsGkAtoms::emptyset, // emptyset 698 nsGkAtoms::eq, // eq 699 nsGkAtoms::equivalent, // equivalent 700 nsGkAtoms::eulergamma, // eulergamma 701 nsGkAtoms::exists, // exists 702 nsGkAtoms::exp, // exp 703 nsGkAtoms::exponentiale, // exponentiale 704 nsGkAtoms::factorial, // factorial 705 nsGkAtoms::factorof, // factorof 706 nsGkAtoms::_false, // false 707 nsGkAtoms::floor, // floor 708 nsGkAtoms::fn, // fn 709 nsGkAtoms::forall, // forall 710 nsGkAtoms::gcd, // gcd 711 nsGkAtoms::geq, // geq 712 nsGkAtoms::grad, // grad 713 nsGkAtoms::gt, // gt 714 nsGkAtoms::ident, // ident 715 nsGkAtoms::image, // image 716 nsGkAtoms::imaginary, // imaginary 717 nsGkAtoms::imaginaryi, // imaginaryi 718 nsGkAtoms::implies, // implies 719 nsGkAtoms::in, // in 720 nsGkAtoms::infinity, // infinity 721 nsGkAtoms::int_, // int 722 nsGkAtoms::integers, // integers 723 nsGkAtoms::intersect, // intersect 724 nsGkAtoms::interval, // interval 725 nsGkAtoms::inverse, // inverse 726 nsGkAtoms::lambda, // lambda 727 nsGkAtoms::laplacian, // laplacian 728 nsGkAtoms::lcm, // lcm 729 nsGkAtoms::leq, // leq 730 nsGkAtoms::limit, // limit 731 nsGkAtoms::list, // list 732 nsGkAtoms::ln, // ln 733 nsGkAtoms::log, // log 734 nsGkAtoms::logbase, // logbase 735 nsGkAtoms::lowlimit, // lowlimit 736 nsGkAtoms::lt, // lt 737 nsGkAtoms::maction, // maction 738 nsGkAtoms::maligngroup, // maligngroup 739 nsGkAtoms::malignmark, // malignmark 740 nsGkAtoms::math, // math 741 nsGkAtoms::matrix, // matrix 742 nsGkAtoms::matrixrow, // matrixrow 743 nsGkAtoms::max, // max 744 nsGkAtoms::mean, // mean 745 nsGkAtoms::median, // median 746 nsGkAtoms::menclose, // menclose 747 nsGkAtoms::merror, // merror 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 StaticAtomSet* nsTreeSanitizer::sElementsHTML = nullptr; 971 StaticAtomSet* nsTreeSanitizer::sAttributesHTML = nullptr; 972 StaticAtomSet* nsTreeSanitizer::sPresAttributesHTML = nullptr; 973 StaticAtomSet* nsTreeSanitizer::sElementsSVG = nullptr; 974 StaticAtomSet* nsTreeSanitizer::sAttributesSVG = nullptr; 975 StaticAtomSet* nsTreeSanitizer::sElementsMathML = nullptr; 976 StaticAtomSet* nsTreeSanitizer::sAttributesMathML = nullptr; 977 nsIPrincipal* nsTreeSanitizer::sNullPrincipal = nullptr; 978 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 if (mCidEmbedsOnly) { 990 // Sanitizing styles for external references is not supported. 991 mAllowStyles = false; 992 } 993 994 if (!sElementsHTML) { 995 // Initialize lazily to avoid having to initialize at all if the user 996 // doesn't paste HTML or load feeds. 997 InitializeStatics(); 998 } 999 } 1000 1001 bool nsTreeSanitizer::MustFlatten(int32_t aNamespace, nsAtom* aLocal) { 1002 if (aNamespace == kNameSpaceID_XHTML) { 1003 if (mDropNonCSSPresentation && 1004 (nsGkAtoms::font == aLocal || nsGkAtoms::center == aLocal)) { 1005 return true; 1006 } 1007 if (mDropForms && 1008 (nsGkAtoms::form == aLocal || nsGkAtoms::input == aLocal || 1009 nsGkAtoms::option == aLocal || nsGkAtoms::optgroup == aLocal)) { 1010 return true; 1011 } 1012 if (mFullDocument && 1013 (nsGkAtoms::title == aLocal || nsGkAtoms::html == aLocal || 1014 nsGkAtoms::head == aLocal || nsGkAtoms::body == aLocal)) { 1015 return false; 1016 } 1017 if (nsGkAtoms::_template == aLocal) { 1018 return false; 1019 } 1020 return !sElementsHTML->Contains(aLocal); 1021 } 1022 if (aNamespace == kNameSpaceID_SVG) { 1023 if (mCidEmbedsOnly || mDropMedia) { 1024 // Sanitizing CSS-based URL references inside SVG presentational 1025 // attributes is not supported, so flattening for cid: embed case. 1026 return true; 1027 } 1028 return !sElementsSVG->Contains(aLocal); 1029 } 1030 if (aNamespace == kNameSpaceID_MathML) { 1031 return !sElementsMathML->Contains(aLocal); 1032 } 1033 return true; 1034 } 1035 1036 bool nsTreeSanitizer::IsURL(const nsStaticAtom* const* aURLs, 1037 nsAtom* aLocalName) { 1038 const nsStaticAtom* atom; 1039 while ((atom = *aURLs)) { 1040 if (atom == aLocalName) { 1041 return true; 1042 } 1043 ++aURLs; 1044 } 1045 return false; 1046 } 1047 1048 bool nsTreeSanitizer::MustPrune(int32_t aNamespace, nsAtom* aLocal, 1049 mozilla::dom::Element* aElement) { 1050 // To avoid attacks where a MathML script becomes something that gets 1051 // serialized in a way that it parses back as an HTML script, let's just 1052 // drop elements with the local name 'script' regardless of namespace. 1053 if (nsGkAtoms::script == aLocal) { 1054 return true; 1055 } 1056 if (aNamespace == kNameSpaceID_XHTML) { 1057 if (nsGkAtoms::title == aLocal && !mFullDocument) { 1058 // emulate the quirks of the old parser 1059 return true; 1060 } 1061 if (mDropForms && 1062 (nsGkAtoms::select == aLocal || nsGkAtoms::button == aLocal || 1063 nsGkAtoms::datalist == aLocal)) { 1064 return true; 1065 } 1066 if (mDropMedia && 1067 (nsGkAtoms::img == aLocal || nsGkAtoms::video == aLocal || 1068 nsGkAtoms::audio == aLocal || nsGkAtoms::source == aLocal)) { 1069 return true; 1070 } 1071 if (nsGkAtoms::meta == aLocal && 1072 (aElement->HasAttr(nsGkAtoms::charset) || 1073 aElement->HasAttr(nsGkAtoms::httpEquiv))) { 1074 // Throw away charset declarations even if they also have microdata 1075 // which they can't validly have. 1076 return true; 1077 } 1078 if (((!mFullDocument && nsGkAtoms::meta == aLocal) || 1079 nsGkAtoms::link == aLocal) && 1080 !(aElement->HasAttr(nsGkAtoms::itemprop) || 1081 aElement->HasAttr(nsGkAtoms::itemscope))) { 1082 // emulate old behavior for non-Microdata <meta> and <link> presumably 1083 // in <head>. <meta> and <link> are whitelisted in order to avoid 1084 // corrupting Microdata when they appear in <body>. Note that 1085 // SanitizeAttributes() will remove the rel attribute from <link> and 1086 // the name attribute from <meta>. 1087 return true; 1088 } 1089 } 1090 if (mAllowStyles) { 1091 return nsGkAtoms::style == aLocal && !(aNamespace == kNameSpaceID_XHTML || 1092 aNamespace == kNameSpaceID_SVG); 1093 } 1094 if (nsGkAtoms::style == aLocal) { 1095 return true; 1096 } 1097 return false; 1098 } 1099 1100 /** 1101 * Parses a style sheet and reserializes it with unsafe styles removed. 1102 * 1103 * @param aOriginal the original style sheet source 1104 * @param aSanitized the reserialization without dangerous CSS. 1105 * @param aDocument the document the style sheet belongs to 1106 * @param aBaseURI the base URI to use 1107 * @param aSanitizationKind the kind of style sanitization to use. 1108 */ 1109 static void SanitizeStyleSheet(const nsAString& aOriginal, 1110 nsAString& aSanitized, Document* aDocument, 1111 nsIURI* aBaseURI, 1112 StyleSanitizationKind aSanitizationKind) { 1113 aSanitized.Truncate(); 1114 1115 NS_ConvertUTF16toUTF8 style(aOriginal); 1116 nsIReferrerInfo* referrer = 1117 aDocument->ReferrerInfoForInternalCSSAndSVGResources(); 1118 auto extraData = 1119 MakeRefPtr<URLExtraData>(aBaseURI, referrer, aDocument->NodePrincipal()); 1120 RefPtr<StyleStylesheetContents> contents = 1121 Servo_StyleSheet_FromUTF8Bytes( 1122 /* loader = */ nullptr, 1123 /* stylesheet = */ nullptr, 1124 /* load_data = */ nullptr, &style, 1125 css::SheetParsingMode::eAuthorSheetFeatures, extraData.get(), 1126 aDocument->GetCompatibilityMode(), 1127 /* reusable_sheets = */ nullptr, StyleAllowImportRules::Yes, 1128 aSanitizationKind, &aSanitized) 1129 .Consume(); 1130 } 1131 1132 bool nsTreeSanitizer::SanitizeInlineStyle( 1133 Element* aElement, StyleSanitizationKind aSanitizationKind) { 1134 MOZ_ASSERT(aElement); 1135 MOZ_ASSERT(aElement->IsHTMLElement(nsGkAtoms::style) || 1136 aElement->IsSVGElement(nsGkAtoms::style)); 1137 1138 nsAutoString styleText; 1139 nsContentUtils::GetNodeTextContent(aElement, false, styleText); 1140 1141 nsAutoString sanitizedStyle; 1142 SanitizeStyleSheet(styleText, sanitizedStyle, aElement->OwnerDoc(), 1143 aElement->GetBaseURI(), StyleSanitizationKind::Standard); 1144 RemoveAllAttributesFromDescendants(aElement); 1145 nsContentUtils::SetNodeTextContent(aElement, sanitizedStyle, true); 1146 1147 return sanitizedStyle.Length() != styleText.Length(); 1148 } 1149 1150 void nsTreeSanitizer::RemoveConditionalCSSFromSubtree(nsINode* aRoot) { 1151 AutoTArray<RefPtr<nsINode>, 10> nodesToSanitize; 1152 for (nsINode* node : ShadowIncludingTreeIterator(*aRoot)) { 1153 if (node->IsHTMLElement(nsGkAtoms::style) || 1154 node->IsSVGElement(nsGkAtoms::style)) { 1155 nodesToSanitize.AppendElement(node); 1156 } 1157 } 1158 for (nsINode* node : nodesToSanitize) { 1159 SanitizeInlineStyle(node->AsElement(), 1160 StyleSanitizationKind::NoConditionalRules); 1161 } 1162 } 1163 1164 template <size_t Len> 1165 static bool UTF16StringStartsWith(const char16_t* aStr, uint32_t aLength, 1166 const char16_t (&aNeedle)[Len]) { 1167 MOZ_ASSERT(aNeedle[Len - 1] == '\0', 1168 "needle should be a UTF-16 encoded string literal"); 1169 1170 if (aLength < Len - 1) { 1171 return false; 1172 } 1173 for (size_t i = 0; i < Len - 1; i++) { 1174 if (aStr[i] != aNeedle[i]) { 1175 return false; 1176 } 1177 } 1178 return true; 1179 } 1180 1181 void nsTreeSanitizer::SanitizeAttributes(mozilla::dom::Element* aElement, 1182 AllowedAttributes aAllowed) { 1183 int32_t ac = (int)aElement->GetAttrCount(); 1184 1185 for (int32_t i = ac - 1; i >= 0; --i) { 1186 const nsAttrName* attrName = aElement->GetAttrNameAt(i); 1187 int32_t attrNs = attrName->NamespaceID(); 1188 RefPtr<nsAtom> attrLocal = attrName->LocalName(); 1189 1190 if (kNameSpaceID_None == attrNs) { 1191 if (aAllowed.mStyle && nsGkAtoms::style == attrLocal) { 1192 continue; 1193 } 1194 if (aAllowed.mDangerousSrc && nsGkAtoms::src == attrLocal) { 1195 continue; 1196 } 1197 if (IsURL(aAllowed.mURLs, attrLocal)) { 1198 bool fragmentOnly = aElement->IsSVGElement(nsGkAtoms::use); 1199 if (SanitizeURL(aElement, attrNs, attrLocal, fragmentOnly)) { 1200 // in case the attribute removal shuffled the attribute order, start 1201 // the loop again. 1202 --ac; 1203 i = ac; // i will be decremented immediately thanks to the for loop 1204 continue; 1205 } 1206 // else fall through to see if there's another reason to drop this 1207 // attribute (in particular if the attribute is background="" on an 1208 // HTML element) 1209 } 1210 if (!mDropNonCSSPresentation && 1211 (aAllowed.mNames == sAttributesHTML) && // element is HTML 1212 sPresAttributesHTML->Contains(attrLocal)) { 1213 continue; 1214 } 1215 if (aAllowed.mNames->Contains(attrLocal) && 1216 !((attrLocal == nsGkAtoms::rel && 1217 aElement->IsHTMLElement(nsGkAtoms::link)) || 1218 (!mFullDocument && attrLocal == nsGkAtoms::name && 1219 aElement->IsHTMLElement(nsGkAtoms::meta)))) { 1220 // name="" and rel="" are whitelisted, but treat them as blacklisted 1221 // for <meta name> (fragment case) and <link rel> (all cases) to avoid 1222 // document-wide metadata or styling overrides with non-conforming 1223 // <meta name itemprop> or 1224 // <link rel itemprop> 1225 continue; 1226 } 1227 const char16_t* localStr = attrLocal->GetUTF16String(); 1228 uint32_t localLen = attrLocal->GetLength(); 1229 // Allow underscore to cater to the MCE editor library. 1230 // Allow data-* on SVG and MathML, too, as a forward-compat measure. 1231 // Allow aria-* on all for simplicity. 1232 if (UTF16StringStartsWith(localStr, localLen, u"_") || 1233 UTF16StringStartsWith(localStr, localLen, u"data-") || 1234 UTF16StringStartsWith(localStr, localLen, u"aria-")) { 1235 continue; 1236 } 1237 // else not allowed 1238 } else if (kNameSpaceID_XML == attrNs) { 1239 if (nsGkAtoms::lang == attrLocal || nsGkAtoms::space == attrLocal) { 1240 continue; 1241 } 1242 // else not allowed 1243 } else if (aAllowed.mXLink && kNameSpaceID_XLink == attrNs) { 1244 if (nsGkAtoms::href == attrLocal) { 1245 bool fragmentOnly = aElement->IsSVGElement(nsGkAtoms::use); 1246 if (SanitizeURL(aElement, attrNs, attrLocal, fragmentOnly)) { 1247 // in case the attribute removal shuffled the attribute order, start 1248 // the loop again. 1249 --ac; 1250 i = ac; // i will be decremented immediately thanks to the for loop 1251 } 1252 continue; 1253 } 1254 if (nsGkAtoms::type == attrLocal || nsGkAtoms::title == attrLocal || 1255 nsGkAtoms::show == attrLocal || nsGkAtoms::actuate == attrLocal) { 1256 continue; 1257 } 1258 // else not allowed 1259 } 1260 aElement->UnsetAttr(kNameSpaceID_None, attrLocal, false); 1261 if (mLogRemovals) { 1262 LogMessage("Removed unsafe attribute.", aElement->OwnerDoc(), aElement, 1263 attrLocal); 1264 } 1265 // in case the attribute removal shuffled the attribute order, start the 1266 // loop again. 1267 --ac; 1268 i = ac; // i will be decremented immediately thanks to the for loop 1269 } 1270 1271 // If we've got HTML audio or video, add the controls attribute, because 1272 // otherwise the content is unplayable with scripts removed. 1273 if (aElement->IsAnyOfHTMLElements(nsGkAtoms::video, nsGkAtoms::audio)) { 1274 aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::controls, u""_ns, false); 1275 } 1276 } 1277 1278 bool nsTreeSanitizer::SanitizeURL(mozilla::dom::Element* aElement, 1279 int32_t aNamespace, nsAtom* aLocalName, 1280 bool aFragmentsOnly) { 1281 nsAutoString value; 1282 aElement->GetAttr(aNamespace, aLocalName, value); 1283 1284 // Get value and remove mandatory quotes 1285 static const char* kWhitespace = "\n\r\t\b"; 1286 const nsAString& v = nsContentUtils::TrimCharsInSet(kWhitespace, value); 1287 // Fragment-only url cannot be harmful. 1288 if (!v.IsEmpty() && v.First() == u'#') { 1289 return false; 1290 } 1291 // if we allow only same-document fragment URLs, stop and remove here 1292 if (aFragmentsOnly) { 1293 aElement->UnsetAttr(aNamespace, aLocalName, false); 1294 if (mLogRemovals) { 1295 LogMessage("Removed unsafe URI from element attribute.", 1296 aElement->OwnerDoc(), aElement, aLocalName); 1297 } 1298 return true; 1299 } 1300 1301 nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager(); 1302 uint32_t flags = nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL; 1303 1304 nsCOMPtr<nsIURI> attrURI; 1305 nsresult rv = 1306 NS_NewURI(getter_AddRefs(attrURI), v, nullptr, aElement->GetBaseURI()); 1307 if (NS_SUCCEEDED(rv)) { 1308 if (mCidEmbedsOnly && kNameSpaceID_None == aNamespace) { 1309 if (nsGkAtoms::src == aLocalName || nsGkAtoms::background == aLocalName) { 1310 // comm-central uses a hack that makes nsIURIs created with cid: specs 1311 // actually have an about:blank spec. Therefore, nsIURI facilities are 1312 // useless for cid: when comm-central code is participating. 1313 if (!(v.Length() > 4 && (v[0] == 'c' || v[0] == 'C') && 1314 (v[1] == 'i' || v[1] == 'I') && (v[2] == 'd' || v[2] == 'D') && 1315 v[3] == ':')) { 1316 rv = NS_ERROR_FAILURE; 1317 } 1318 } else if (nsGkAtoms::cdgroup == aLocalName || 1319 nsGkAtoms::altimg == aLocalName || 1320 nsGkAtoms::definitionURL == aLocalName) { 1321 // Gecko doesn't fetch these now and shouldn't in the future, but 1322 // in case someone goofs with these in the future, let's drop them. 1323 rv = NS_ERROR_FAILURE; 1324 } else { 1325 rv = secMan->CheckLoadURIWithPrincipal(sNullPrincipal, attrURI, flags, 1326 0); 1327 } 1328 } else { 1329 rv = secMan->CheckLoadURIWithPrincipal(sNullPrincipal, attrURI, flags, 0); 1330 } 1331 } 1332 if (NS_FAILED(rv)) { 1333 aElement->UnsetAttr(aNamespace, aLocalName, false); 1334 if (mLogRemovals) { 1335 LogMessage("Removed unsafe URI from element attribute.", 1336 aElement->OwnerDoc(), aElement, aLocalName); 1337 } 1338 return true; 1339 } 1340 return false; 1341 } 1342 1343 void nsTreeSanitizer::Sanitize(DocumentFragment* aFragment) { 1344 // If you want to relax these preconditions, be sure to check the code in 1345 // here that notifies / does not notify or that fires mutation events if 1346 // in tree. 1347 MOZ_ASSERT(!aFragment->IsInUncomposedDoc(), "The fragment is in doc?"); 1348 1349 mFullDocument = false; 1350 SanitizeChildren(aFragment); 1351 } 1352 1353 void nsTreeSanitizer::Sanitize(Document* aDocument) { 1354 // If you want to relax these preconditions, be sure to check the code in 1355 // here that notifies / does not notify or that fires mutation events if 1356 // in tree. 1357 #ifdef DEBUG 1358 MOZ_ASSERT(!aDocument->GetContainer(), "The document is in a shell."); 1359 RefPtr<mozilla::dom::Element> root = aDocument->GetRootElement(); 1360 MOZ_ASSERT(root->IsHTMLElement(nsGkAtoms::html), "Not HTML root."); 1361 #endif 1362 1363 mFullDocument = true; 1364 SanitizeChildren(aDocument); 1365 } 1366 1367 void nsTreeSanitizer::SanitizeChildren(nsINode* aRoot) { 1368 nsIContent* node = aRoot->GetFirstChild(); 1369 while (node) { 1370 if (node->IsElement()) { 1371 mozilla::dom::Element* elt = node->AsElement(); 1372 mozilla::dom::NodeInfo* nodeInfo = node->NodeInfo(); 1373 nsAtom* localName = nodeInfo->NameAtom(); 1374 int32_t ns = nodeInfo->NamespaceID(); 1375 1376 if (MustPrune(ns, localName, elt)) { 1377 if (mLogRemovals) { 1378 LogMessage("Removing unsafe node.", elt->OwnerDoc(), elt); 1379 } 1380 RemoveAllAttributes(elt); 1381 nsIContent* descendant = node; 1382 while ((descendant = descendant->GetNextNode(node))) { 1383 if (descendant->IsElement()) { 1384 RemoveAllAttributes(descendant->AsElement()); 1385 } 1386 } 1387 nsIContent* next = node->GetNextNonChildNode(aRoot); 1388 node->RemoveFromParent(); 1389 node = next; 1390 continue; 1391 } 1392 if (auto* templateEl = HTMLTemplateElement::FromNode(elt)) { 1393 // traverse into the DocFragment content attribute of template elements 1394 bool wasFullDocument = mFullDocument; 1395 mFullDocument = false; 1396 RefPtr<DocumentFragment> frag = templateEl->Content(); 1397 SanitizeChildren(frag); 1398 mFullDocument = wasFullDocument; 1399 } 1400 if (nsGkAtoms::style == localName) { 1401 // If styles aren't allowed, style elements got pruned above. Even 1402 // if styles are allowed, non-HTML, non-SVG style elements got pruned 1403 // above. 1404 NS_ASSERTION(ns == kNameSpaceID_XHTML || ns == kNameSpaceID_SVG, 1405 "Should have only HTML or SVG here!"); 1406 if (SanitizeInlineStyle(elt, StyleSanitizationKind::Standard) && 1407 mLogRemovals) { 1408 LogMessage("Removed some rules and/or properties from stylesheet.", 1409 aRoot->OwnerDoc()); 1410 } 1411 1412 AllowedAttributes allowed; 1413 allowed.mStyle = mAllowStyles; 1414 if (ns == kNameSpaceID_XHTML) { 1415 allowed.mNames = sAttributesHTML; 1416 allowed.mURLs = kURLAttributesHTML; 1417 } else { 1418 allowed.mNames = sAttributesSVG; 1419 allowed.mURLs = kURLAttributesSVG; 1420 allowed.mXLink = true; 1421 } 1422 SanitizeAttributes(elt, allowed); 1423 node = node->GetNextNonChildNode(aRoot); 1424 continue; 1425 } 1426 if (MustFlatten(ns, localName)) { 1427 if (mLogRemovals) { 1428 LogMessage("Flattening unsafe node (descendants are preserved).", 1429 elt->OwnerDoc(), elt); 1430 } 1431 RemoveAllAttributes(elt); 1432 nsCOMPtr<nsIContent> next = node->GetNextNode(aRoot); 1433 nsCOMPtr<nsIContent> parent = node->GetParent(); 1434 nsCOMPtr<nsIContent> child; // Must keep the child alive during move 1435 ErrorResult rv; 1436 while ((child = node->GetFirstChild())) { 1437 nsCOMPtr<nsINode> refNode = node; 1438 parent->InsertBeforeInternal( 1439 *child, refNode, MutationEffectOnScript::KeepTrustWorthiness, rv); 1440 if (rv.Failed()) { 1441 break; 1442 } 1443 } 1444 node->RemoveFromParent(); 1445 node = next; 1446 continue; 1447 } 1448 NS_ASSERTION(ns == kNameSpaceID_XHTML || ns == kNameSpaceID_SVG || 1449 ns == kNameSpaceID_MathML, 1450 "Should have only HTML, MathML or SVG here!"); 1451 AllowedAttributes allowed; 1452 if (ns == kNameSpaceID_XHTML) { 1453 allowed.mNames = sAttributesHTML; 1454 allowed.mURLs = kURLAttributesHTML; 1455 allowed.mStyle = mAllowStyles; 1456 allowed.mDangerousSrc = nsGkAtoms::img == localName && !mCidEmbedsOnly; 1457 SanitizeAttributes(elt, allowed); 1458 } else if (ns == kNameSpaceID_SVG) { 1459 allowed.mNames = sAttributesSVG; 1460 allowed.mURLs = kURLAttributesSVG; 1461 allowed.mXLink = true; 1462 allowed.mStyle = mAllowStyles; 1463 SanitizeAttributes(elt, allowed); 1464 } else { 1465 allowed.mNames = sAttributesMathML; 1466 allowed.mURLs = kURLAttributesMathML; 1467 allowed.mXLink = true; 1468 SanitizeAttributes(elt, allowed); 1469 } 1470 node = node->GetNextNode(aRoot); 1471 continue; 1472 } 1473 NS_ASSERTION(!node->GetFirstChild(), "How come non-element node had kids?"); 1474 nsIContent* next = node->GetNextNonChildNode(aRoot); 1475 if (!mAllowComments && node->IsComment()) { 1476 node->RemoveFromParent(); 1477 } 1478 node = next; 1479 } 1480 } 1481 1482 void nsTreeSanitizer::RemoveAllAttributes(Element* aElement) { 1483 const nsAttrName* attrName; 1484 while (aElement->GetAttrNameAt(0, &attrName)) { 1485 int32_t attrNs = attrName->NamespaceID(); 1486 RefPtr<nsAtom> attrLocal = attrName->LocalName(); 1487 aElement->UnsetAttr(attrNs, attrLocal, false); 1488 } 1489 } 1490 1491 void nsTreeSanitizer::RemoveAllAttributesFromDescendants( 1492 mozilla::dom::Element* aElement) { 1493 nsIContent* node = aElement->GetFirstChild(); 1494 while (node) { 1495 if (node->IsElement()) { 1496 mozilla::dom::Element* elt = node->AsElement(); 1497 RemoveAllAttributes(elt); 1498 } 1499 node = node->GetNextNode(aElement); 1500 } 1501 } 1502 1503 void nsTreeSanitizer::LogMessage(const char* aMessage, Document* aDoc, 1504 Element* aElement, nsAtom* aAttr) { 1505 if (mLogRemovals) { 1506 nsAutoString msg; 1507 msg.AssignASCII(aMessage); 1508 if (aElement) { 1509 msg.Append(u" Element: "_ns + aElement->LocalName() + u"."_ns); 1510 } 1511 if (aAttr) { 1512 msg.Append(u" Attribute: "_ns + nsDependentAtomString(aAttr) + u"."_ns); 1513 } 1514 1515 nsContentUtils::ReportToConsoleNonLocalized( 1516 msg, nsIScriptError::warningFlag, "DOM"_ns, aDoc); 1517 } 1518 } 1519 1520 void nsTreeSanitizer::InitializeStatics() { 1521 MOZ_ASSERT(!sElementsHTML, "Initializing a second time."); 1522 1523 sElementsHTML = new StaticAtomSet(std::size(kElementsHTML)); 1524 for (uint32_t i = 0; kElementsHTML[i]; i++) { 1525 sElementsHTML->Insert(kElementsHTML[i]); 1526 } 1527 1528 sAttributesHTML = new StaticAtomSet(std::size(kAttributesHTML)); 1529 for (uint32_t i = 0; kAttributesHTML[i]; i++) { 1530 sAttributesHTML->Insert(kAttributesHTML[i]); 1531 } 1532 1533 sPresAttributesHTML = new StaticAtomSet(std::size(kPresAttributesHTML)); 1534 for (uint32_t i = 0; kPresAttributesHTML[i]; i++) { 1535 sPresAttributesHTML->Insert(kPresAttributesHTML[i]); 1536 } 1537 1538 sElementsSVG = new StaticAtomSet(std::size(kElementsSVG)); 1539 for (uint32_t i = 0; kElementsSVG[i]; i++) { 1540 sElementsSVG->Insert(kElementsSVG[i]); 1541 } 1542 1543 sAttributesSVG = new StaticAtomSet(std::size(kAttributesSVG)); 1544 for (uint32_t i = 0; kAttributesSVG[i]; i++) { 1545 sAttributesSVG->Insert(kAttributesSVG[i]); 1546 } 1547 1548 sElementsMathML = new StaticAtomSet(std::size(kElementsMathML)); 1549 for (uint32_t i = 0; kElementsMathML[i]; i++) { 1550 sElementsMathML->Insert(kElementsMathML[i]); 1551 } 1552 1553 sAttributesMathML = new StaticAtomSet(std::size(kAttributesMathML)); 1554 for (uint32_t i = 0; kAttributesMathML[i]; i++) { 1555 sAttributesMathML->Insert(kAttributesMathML[i]); 1556 } 1557 1558 nsCOMPtr<nsIPrincipal> principal = 1559 NullPrincipal::CreateWithoutOriginAttributes(); 1560 principal.forget(&sNullPrincipal); 1561 } 1562 1563 void nsTreeSanitizer::ReleaseStatics() { 1564 delete sElementsHTML; 1565 sElementsHTML = nullptr; 1566 1567 delete sAttributesHTML; 1568 sAttributesHTML = nullptr; 1569 1570 delete sPresAttributesHTML; 1571 sPresAttributesHTML = nullptr; 1572 1573 delete sElementsSVG; 1574 sElementsSVG = nullptr; 1575 1576 delete sAttributesSVG; 1577 sAttributesSVG = nullptr; 1578 1579 delete sElementsMathML; 1580 sElementsMathML = nullptr; 1581 1582 delete sAttributesMathML; 1583 sAttributesMathML = nullptr; 1584 1585 NS_IF_RELEASE(sNullPrincipal); 1586 }