Version 2.12.3
* Cherry-pick ce5a1c2392debce967415d4c09359ff2555e3588 to stable
* Cherry-pick adc36a6563614a7c3ba29d9911e57fc68e7d9ac0 to stable
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 70b454a..e2d2fb1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 2.12.3 - 2021-04-12
+
+This is a patch release that fixes a vulnerability in `dart:html` related to
+DOM clobbering. Thanks again to **Vincenzo di Cicco** for finding and reporting
+this vulnerability.
+
## 2.12.2 - 2021-03-17
This is a patch release that fixes crashes reported by Flutter 2 users (issue
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index bc7bdfb..c60be00 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -40994,8 +40994,8 @@
class _ValidatingTreeSanitizer implements NodeTreeSanitizer {
NodeValidator validator;
- /// Did we modify the tree by removing anything.
- bool modifiedTree = false;
+ /// Number of tree modifications this instance has made.
+ int numTreeModifications = 0;
_ValidatingTreeSanitizer(this.validator) {}
void sanitizeTree(Node node) {
@@ -41026,12 +41026,12 @@
}
}
- modifiedTree = false;
- walk(node, null);
- while (modifiedTree) {
- modifiedTree = false;
+ // Walk the tree until no new modifications are added to the tree.
+ var previousTreeModifications;
+ do {
+ previousTreeModifications = numTreeModifications;
walk(node, null);
- }
+ } while (previousTreeModifications != numTreeModifications);
}
/// Aggressively try to remove node.
@@ -41039,7 +41039,7 @@
// If we have the parent, it's presumably already passed more sanitization
// or is the fragment, so ask it to remove the child. And if that fails
// try to set the outer html.
- modifiedTree = true;
+ numTreeModifications++;
if (parent == null || parent != node.parentNode) {
node.remove();
} else {
diff --git a/tests/lib/html/node_validator_important_if_you_suppress_make_the_bug_critical_test.dart b/tests/lib/html/node_validator_important_if_you_suppress_make_the_bug_critical_test.dart
index 5a3d0f2..2d7205c 100644
--- a/tests/lib/html/node_validator_important_if_you_suppress_make_the_bug_critical_test.dart
+++ b/tests/lib/html/node_validator_important_if_you_suppress_make_the_bug_critical_test.dart
@@ -453,6 +453,20 @@
"<input id='bad' onmouseover='alert(1)'>",
"");
+ // Walking templates triggers a recursive sanitization call, which shouldn't
+ // invalidate the information collected from the previous visit of the later
+ // nodes in the walk.
+ testHtml(
+ 'DOM clobbering with recursive sanitize call using templates',
+ validator,
+ "<form><div>"
+ "<input id=childNodes />"
+ "<template></template>"
+ "<input id=childNodes name=lastChild />"
+ "<img id=exploitImg src=0 onerror='alert(1)' />"
+ "</div></form>",
+ "");
+
test('tagName makes containing form invalid', () {
var fragment = document.body!.createFragment(
"<form onmouseover='alert(2)'><input name='tagName'>",
diff --git a/tests/lib_2/html/node_validator_important_if_you_suppress_make_the_bug_critical_test.dart b/tests/lib_2/html/node_validator_important_if_you_suppress_make_the_bug_critical_test.dart
index 1b3ea60..ee31868 100644
--- a/tests/lib_2/html/node_validator_important_if_you_suppress_make_the_bug_critical_test.dart
+++ b/tests/lib_2/html/node_validator_important_if_you_suppress_make_the_bug_critical_test.dart
@@ -478,6 +478,20 @@
"<input id='bad' onmouseover='alert(1)'>",
"");
+ // Walking templates triggers a recursive sanitization call, which shouldn't
+ // invalidate the information collected from the previous visit of the later
+ // nodes in the walk.
+ testHtml(
+ 'DOM clobbering with recursive sanitize call using templates',
+ validator,
+ "<form><div>"
+ "<input id=childNodes />"
+ "<template></template>"
+ "<input id=childNodes name=lastChild />"
+ "<img id=exploitImg src=0 onerror='alert(1)' />"
+ "</div></form>",
+ "");
+
test('tagName makes containing form invalid', () {
var fragment = document.body.createFragment(
"<form onmouseover='alert(2)'><input name='tagName'>",
diff --git a/tools/VERSION b/tools/VERSION
index ec4c8b7..6f1acdf 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -26,6 +26,6 @@
CHANNEL stable
MAJOR 2
MINOR 12
-PATCH 2
+PATCH 3
PRERELEASE 0
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/dom/src/Validators.dart b/tools/dom/src/Validators.dart
index 0c45b8c..1fbafbd 100644
--- a/tools/dom/src/Validators.dart
+++ b/tools/dom/src/Validators.dart
@@ -158,8 +158,8 @@
class _ValidatingTreeSanitizer implements NodeTreeSanitizer {
NodeValidator validator;
- /// Did we modify the tree by removing anything.
- bool modifiedTree = false;
+ /// Number of tree modifications this instance has made.
+ int numTreeModifications = 0;
_ValidatingTreeSanitizer(this.validator) {}
void sanitizeTree(Node node) {
@@ -190,12 +190,12 @@
}
}
- modifiedTree = false;
- walk(node, null);
- while (modifiedTree) {
- modifiedTree = false;
+ // Walk the tree until no new modifications are added to the tree.
+ var previousTreeModifications;
+ do {
+ previousTreeModifications = numTreeModifications;
walk(node, null);
- }
+ } while (previousTreeModifications != numTreeModifications);
}
/// Aggressively try to remove node.
@@ -203,7 +203,7 @@
// If we have the parent, it's presumably already passed more sanitization
// or is the fragment, so ask it to remove the child. And if that fails
// try to set the outer html.
- modifiedTree = true;
+ numTreeModifications++;
if (parent == null || parent != node.parentNode) {
node.remove();
} else {