From 614b2206a03a411306f3a4fda15118379d91d1c9 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 19 Dec 2023 16:31:04 +0100 Subject: [PATCH 1/7] Add test for oob string lookup --- tests/phpunit/tests/html-api/wpHtmlTagProcessor.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php index 4469f90c4f276..a5fb8d2b9bffc 100644 --- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php @@ -2428,6 +2428,15 @@ public function test_updating_attributes_in_malformed_html( $html, $expected ) { ); } + /** + * @covers WP_HTML_Tag_Processor::next_tag + */ + public function test_handles_malformed_taglike_open_short_html() { + $p = new WP_HTML_Tag_Processor( "<" ); + $result = $p->next_tag(); + $this->assertFalse( $result, 'Did not handle "<" html properly.' ); + } + /** * Data provider. * From 8bfb6131ddcd18ee60ed1fa81ddd891c9bdedd92 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 19 Dec 2023 16:33:07 +0100 Subject: [PATCH 2/7] Check for in-range index --- src/wp-includes/html-api/class-wp-html-tag-processor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/html-api/class-wp-html-tag-processor.php b/src/wp-includes/html-api/class-wp-html-tag-processor.php index 17b3f400fcea6..75a1832de2a64 100644 --- a/src/wp-includes/html-api/class-wp-html-tag-processor.php +++ b/src/wp-includes/html-api/class-wp-html-tag-processor.php @@ -1113,7 +1113,7 @@ private function parse_next_tag() { $this->token_starts_at = $at; - if ( '/' === $this->html[ $at + 1 ] ) { + if ( $doc_length > $at + 1 && '/' === $this->html[ $at + 1 ] ) { $this->is_closing_tag = true; ++$at; } else { From 8579278493488f095a58452d71429c791477b70d Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 19 Dec 2023 16:34:16 +0100 Subject: [PATCH 3/7] Fix lints --- tests/phpunit/tests/html-api/wpHtmlTagProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php index a5fb8d2b9bffc..7aa8ad7caefb8 100644 --- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php @@ -2432,7 +2432,7 @@ public function test_updating_attributes_in_malformed_html( $html, $expected ) { * @covers WP_HTML_Tag_Processor::next_tag */ public function test_handles_malformed_taglike_open_short_html() { - $p = new WP_HTML_Tag_Processor( "<" ); + $p = new WP_HTML_Tag_Processor( '<' ); $result = $p->next_tag(); $this->assertFalse( $result, 'Did not handle "<" html properly.' ); } From 4e016343391f01328b0e1408a5d65b4c73c37c06 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 19 Dec 2023 16:49:14 +0100 Subject: [PATCH 4/7] Add out of range closer test --- tests/phpunit/tests/html-api/wpHtmlTagProcessor.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php index 7aa8ad7caefb8..5c4bb3afc6b8d 100644 --- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php @@ -2437,6 +2437,15 @@ public function test_handles_malformed_taglike_open_short_html() { $this->assertFalse( $result, 'Did not handle "<" html properly.' ); } + /** + * @covers WP_HTML_Tag_Processor::next_tag + */ + public function test_handles_malformed_taglike_close_short_html() { + $p = new WP_HTML_Tag_Processor( 'next_tag(); + $this->assertFalse( $result, 'Did not handle " Date: Tue, 19 Dec 2023 17:07:44 +0100 Subject: [PATCH 5/7] Fix oob check --- src/wp-includes/html-api/class-wp-html-tag-processor.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/wp-includes/html-api/class-wp-html-tag-processor.php b/src/wp-includes/html-api/class-wp-html-tag-processor.php index 75a1832de2a64..8b920b1098dcb 100644 --- a/src/wp-includes/html-api/class-wp-html-tag-processor.php +++ b/src/wp-includes/html-api/class-wp-html-tag-processor.php @@ -1290,6 +1290,11 @@ private function parse_next_tag() { * See https://html.spec.whatwg.org/#parse-error-invalid-first-character-of-tag-name */ if ( $this->is_closing_tag ) { + // No chance of finding a closer + if ( $at + 3 > $doc_length ) { + return false; + } + $closer_at = strpos( $html, '>', $at + 3 ); if ( false === $closer_at ) { return false; From 69a79658f1d1fb86a9a4a292dd4d9d65fa2886e4 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 19 Dec 2023 17:09:12 +0100 Subject: [PATCH 6/7] Use stored doc_length over strlen() calls --- .../html-api/class-wp-html-tag-processor.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/wp-includes/html-api/class-wp-html-tag-processor.php b/src/wp-includes/html-api/class-wp-html-tag-processor.php index 8b920b1098dcb..f66b759faeec6 100644 --- a/src/wp-includes/html-api/class-wp-html-tag-processor.php +++ b/src/wp-includes/html-api/class-wp-html-tag-processor.php @@ -1147,7 +1147,7 @@ private function parse_next_tag() { * Abort if no tag is found before the end of * the document. There is nothing left to parse. */ - if ( $at + 1 >= strlen( $html ) ) { + if ( $at + 1 >= $doc_length ) { return false; } @@ -1161,13 +1161,13 @@ private function parse_next_tag() { * https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state */ if ( - strlen( $html ) > $at + 3 && + $doc_length > $at + 3 && '-' === $html[ $at + 2 ] && '-' === $html[ $at + 3 ] ) { $closer_at = $at + 4; // If it's not possible to close the comment then there is nothing more to scan. - if ( strlen( $html ) <= $closer_at ) { + if ( $doc_length <= $closer_at ) { return false; } @@ -1185,18 +1185,18 @@ private function parse_next_tag() { * See https://html.spec.whatwg.org/#parse-error-incorrectly-closed-comment */ --$closer_at; // Pre-increment inside condition below reduces risk of accidental infinite looping. - while ( ++$closer_at < strlen( $html ) ) { + while ( ++$closer_at < $doc_length ) { $closer_at = strpos( $html, '--', $closer_at ); if ( false === $closer_at ) { return false; } - if ( $closer_at + 2 < strlen( $html ) && '>' === $html[ $closer_at + 2 ] ) { + if ( $closer_at + 2 < $doc_length && '>' === $html[ $closer_at + 2 ] ) { $at = $closer_at + 3; continue 2; } - if ( $closer_at + 3 < strlen( $html ) && '!' === $html[ $closer_at + 2 ] && '>' === $html[ $closer_at + 3 ] ) { + if ( $closer_at + 3 < $doc_length && '!' === $html[ $closer_at + 2 ] && '>' === $html[ $closer_at + 3 ] ) { $at = $closer_at + 4; continue 2; } @@ -1209,7 +1209,7 @@ private function parse_next_tag() { * https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state */ if ( - strlen( $html ) > $at + 8 && + $doc_length > $at + 8 && '[' === $html[ $at + 2 ] && 'C' === $html[ $at + 3 ] && 'D' === $html[ $at + 4 ] && @@ -1233,7 +1233,7 @@ private function parse_next_tag() { * https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state */ if ( - strlen( $html ) > $at + 8 && + $doc_length > $at + 8 && ( 'D' === $html[ $at + 2 ] || 'd' === $html[ $at + 2 ] ) && ( 'O' === $html[ $at + 3 ] || 'o' === $html[ $at + 3 ] ) && ( 'C' === $html[ $at + 4 ] || 'c' === $html[ $at + 4 ] ) && From 8905faf8fd390eb888a25a8f546a66e2feccd2c5 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 19 Dec 2023 17:17:01 +0100 Subject: [PATCH 7/7] Fix lints --- tests/phpunit/tests/html-api/wpHtmlTagProcessor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php index 5c4bb3afc6b8d..58aa7dcb60670 100644 --- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php @@ -2432,7 +2432,7 @@ public function test_updating_attributes_in_malformed_html( $html, $expected ) { * @covers WP_HTML_Tag_Processor::next_tag */ public function test_handles_malformed_taglike_open_short_html() { - $p = new WP_HTML_Tag_Processor( '<' ); + $p = new WP_HTML_Tag_Processor( '<' ); $result = $p->next_tag(); $this->assertFalse( $result, 'Did not handle "<" html properly.' ); } @@ -2441,7 +2441,7 @@ public function test_handles_malformed_taglike_open_short_html() { * @covers WP_HTML_Tag_Processor::next_tag */ public function test_handles_malformed_taglike_close_short_html() { - $p = new WP_HTML_Tag_Processor( 'next_tag(); $this->assertFalse( $result, 'Did not handle "