Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ PHP NEWS
. Fixed a crash when converting with a cloned UConverter that uses
toUCallback/fromUCallback. (Ilia Alshanetsky)

- Lexbor:
. Merge patches lexbor/lexbor@8a14bc0 and lexbor/lexbor@f67ce4b, fixing a
heap buffer overflow in :lexbor-contains() parsing and buffer overflows
in malformed decode replay. (alexandre-daubois)

- MBString:
. Fixed bug GH-23106 (mb_strpos() reads past the end of a haystack ending in
a truncated UTF-8 sequence). (Lazizbek Ergashev)
Expand Down
16 changes: 16 additions & 0 deletions ext/dom/tests/modern/css_selectors/lexbor_contains.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
CSS Selectors - Pseudo classes: :lexbor-contains() with an argument longer than its string header
--EXTENSIONS--
dom
--FILE--
<?php

$dom = Dom\HTMLDocument::createFromString('<p>needle</p>', LIBXML_NOERROR);

var_dump($dom->querySelectorAll(':lexbor-contains("' . str_repeat('needle', 1024) . '")')->length);
var_dump($dom->querySelectorAll(':lexbor-contains("needle")')->length);

?>
--EXPECT--
int(0)
int(0)
5 changes: 2 additions & 3 deletions ext/lexbor/lexbor/css/selectors/pseudo_state.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,13 +227,12 @@ lxb_css_selectors_state_pseudo_class_function_lexbor_contains(lxb_css_parser_t *
contains->insensitive = false;
str = &contains->str;

str->data = lexbor_mraw_alloc(parser->memory->mraw,
sizeof(lexbor_str_t));
str->data = lexbor_mraw_alloc(parser->memory->mraw, length + 1);
if (str->data == NULL) {
return lxb_css_parser_memory_fail(parser);
}

memcpy(str->data, data, length + 1);
memcpy(str->data, data, length);

str->length = length;
str->data[length] = '\0';
Expand Down
37 changes: 33 additions & 4 deletions ext/lexbor/lexbor/encoding/decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,13 @@ lxb_encoding_decode_iso_2022_jp(lxb_encoding_decode_t *ctx,
}
LXB_ENCODING_DECODE_ERROR_END();

if (ctx->buffer_used >= ctx->buffer_length) {
iso->prepand = iso->lead;
iso->lead = 0x00;

return LXB_STATUS_SMALL_BUFFER;
}

byte = iso->lead;
iso->lead = 0x00;

Expand Down Expand Up @@ -1279,6 +1286,12 @@ lxb_encoding_decode_utf_16(lxb_encoding_decode_t *ctx, bool is_be,
}
LXB_ENCODING_DECODE_ERROR_END();

if (ctx->buffer_used >= ctx->buffer_length) {
ctx->u.lead = lead + 0x01;

return LXB_STATUS_SMALL_BUFFER;
}

goto lead_state;
}

Expand Down Expand Up @@ -1723,6 +1736,13 @@ lxb_encoding_decode_gb18030(lxb_encoding_decode_t *ctx,
}
LXB_ENCODING_DECODE_ERROR_END();

if (ctx->buffer_used >= ctx->buffer_length) {
ctx->prepend = true;
ctx->u.gb18030.first = second;

return LXB_STATUS_SMALL_BUFFER;
}

first = second;

goto prepend_first;
Expand Down Expand Up @@ -1756,11 +1776,8 @@ lxb_encoding_decode_gb18030(lxb_encoding_decode_t *ctx,
}
LXB_ENCODING_DECODE_ERROR_END();

LXB_ENCODING_DECODE_APPEND_WO_CHECK(ctx, second);

if (ctx->buffer_used == ctx->buffer_length) {
if (ctx->buffer_used >= ctx->buffer_length) {
ctx->prepend = true;
ctx->have_error = true;

/* First is a fake for trigger */
ctx->u.gb18030.first = 0x01;
Expand All @@ -1770,6 +1787,18 @@ lxb_encoding_decode_gb18030(lxb_encoding_decode_t *ctx,
return LXB_STATUS_SMALL_BUFFER;
}

LXB_ENCODING_DECODE_APPEND_WO_CHECK(ctx, second);

if (ctx->buffer_used >= ctx->buffer_length) {
ctx->prepend = true;

ctx->u.gb18030.first = third;
ctx->u.gb18030.second = 0x00;
ctx->u.gb18030.third = 0x00;

return LXB_STATUS_SMALL_BUFFER;
}

first = third;

goto prepend_first;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
Date: Sat, 26 Aug 2023 15:08:59 +0200
Subject: [PATCH 01/13] Expose line and column information for use in PHP
Subject: [PATCH 01/15] Expose line and column information for use in PHP

---
source/lexbor/dom/interfaces/node.h | 2 ++
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
Date: Mon, 14 Aug 2023 20:18:51 +0200
Subject: [PATCH 02/13] Track implied added nodes for options use in PHP
Subject: [PATCH 02/15] Track implied added nodes for options use in PHP

---
source/lexbor/html/tree.h | 3 +++
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
Date: Thu, 24 Aug 2023 22:57:48 +0200
Subject: [PATCH 03/13] Patch utilities and data structure to be able to
Subject: [PATCH 03/15] Patch utilities and data structure to be able to
generate smaller lookup tables

Changed the generation script to check if everything fits in 32-bits.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
Date: Wed, 29 Nov 2023 21:26:47 +0100
Subject: [PATCH 04/13] Remove unused upper case tag static data
Subject: [PATCH 04/15] Remove unused upper case tag static data

---
source/lexbor/tag/res.h | 2 ++
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
Date: Wed, 29 Nov 2023 21:29:31 +0100
Subject: [PATCH 05/13] Shrink size of static binary search tree
Subject: [PATCH 05/15] Shrink size of static binary search tree

This also makes it more efficient on the data cache.
---
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
Date: Sun, 7 Jan 2024 21:59:28 +0100
Subject: [PATCH 06/13] Patch out unused CSS style code
Subject: [PATCH 06/15] Patch out unused CSS style code

---
source/lexbor/css/rule.h | 2 ++
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= <kocsismate@woohoolabs.com>
Date: Sun, 17 May 2026 22:17:14 +0200
Subject: [PATCH 07/13] Add lxb_url_is_special() to the public API (#362)
Subject: [PATCH 07/15] Add lxb_url_is_special() to the public API (#362)

As https://wiki.php.net/rfc/uri_followup#uri_type_detection relies on this information.
---
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alexander Borisov <lex.borisov@gmail.com>
Date: Fri, 26 Jun 2026 18:55:56 +0300
Subject: [PATCH 08/13] URL: fixed setters for empty hosts.
Subject: [PATCH 08/15] URL: fixed setters for empty hosts.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alexander Borisov <lex.borisov@gmail.com>
Date: Fri, 5 Jun 2026 22:13:32 +0300
Subject: [PATCH 09/13] URL: fixed uninitialized memory in the path buffer
Subject: [PATCH 09/15] URL: fixed uninitialized memory in the path buffer
growth.

When a path was long enough to outgrow the on-stack buffer, the first
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= <kocsismate@woohoolabs.com>
Date: Thu, 9 Jul 2026 21:51:05 +0200
Subject: [PATCH 10/13] Fix parsing for URL containing empty host and userinfo
Subject: [PATCH 10/15] Fix parsing for URL containing empty host and userinfo

The returned error code (LXB_URL_ERROR_TYPE_INVALID_CREDENTIALS) apparently contradicts the specification:

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= <kocsismate@woohoolabs.com>
Date: Fri, 10 Jul 2026 22:31:16 +0200
Subject: [PATCH 11/13] Percent-encode the caret in the path
Subject: [PATCH 11/15] Percent-encode the caret in the path

The caret (^) is part of the path percent-encode set:

Expand Down
2 changes: 1 addition & 1 deletion ext/lexbor/patches/0012-URL-added-public-IPv6-parser.patch
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alexander Borisov <lex.borisov@gmail.com>
Date: Wed, 12 Aug 2026 23:29:20 +0300
Subject: [PATCH 12/13] URL: added public IPv6 parser.
Subject: [PATCH 12/15] URL: added public IPv6 parser.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alexander Borisov <lex.borisov@gmail.com>
Date: Thu, 13 Aug 2026 23:29:16 +0300
Subject: [PATCH 13/13] URL: added public percent-encoder API.
Subject: [PATCH 13/15] URL: added public percent-encoder API.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alexander Borisov <lex.borisov@gmail.com>
Date: Fri, 5 Jun 2026 22:34:23 +0300
Subject: [PATCH 14/15] CSS: fixed heap buffer overflow in :lexbor-contains()
parsing.

The contains string buffer was allocated by the size of the string
structure instead of the content length, so any value longer than
that overflowed the buffer.

Per report from Xiansheng Cao (@HMF2021)
---
source/lexbor/css/selectors/pseudo_state.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/source/lexbor/css/selectors/pseudo_state.c b/source/lexbor/css/selectors/pseudo_state.c
index 263ca52..2321ddf 100644
--- a/source/lexbor/css/selectors/pseudo_state.c
+++ b/source/lexbor/css/selectors/pseudo_state.c
@@ -227,13 +227,12 @@ again:
contains->insensitive = false;
str = &contains->str;

- str->data = lexbor_mraw_alloc(parser->memory->mraw,
- sizeof(lexbor_str_t));
+ str->data = lexbor_mraw_alloc(parser->memory->mraw, length + 1);
if (str->data == NULL) {
return lxb_css_parser_memory_fail(parser);
}

- memcpy(str->data, data, length + 1);
+ memcpy(str->data, data, length);

str->length = length;
str->data[length] = '\0';
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alexander Borisov <lex.borisov@gmail.com>
Date: Wed, 10 Jun 2026 19:50:10 +0300
Subject: [PATCH 15/15] Encoding: fixed buffer overflows in malformed decode
replay.

Fixed out-of-bounds writes in buffering decoders when replacement output
fills the caller-provided codepoint buffer and decoder replay continues in
the same call.

Affected decoders:
- GB18030 malformed third/fourth byte replay.
- ISO-2022-JP malformed escape replay.
- UTF-16BE/LE invalid surrogate replay.

Per report from @hurric9-droid on GitHub.
---
source/lexbor/encoding/decode.c | 37 +++++++++++++++++++++++++++++----
1 file changed, 33 insertions(+), 4 deletions(-)

diff --git a/source/lexbor/encoding/decode.c b/source/lexbor/encoding/decode.c
index 3e48971..05c4b9b 100644
--- a/source/lexbor/encoding/decode.c
+++ b/source/lexbor/encoding/decode.c
@@ -912,6 +912,13 @@ lxb_encoding_decode_iso_2022_jp(lxb_encoding_decode_t *ctx,
}
LXB_ENCODING_DECODE_ERROR_END();

+ if (ctx->buffer_used >= ctx->buffer_length) {
+ iso->prepand = iso->lead;
+ iso->lead = 0x00;
+
+ return LXB_STATUS_SMALL_BUFFER;
+ }
+
byte = iso->lead;
iso->lead = 0x00;

@@ -1279,6 +1286,12 @@ lxb_encoding_decode_utf_16(lxb_encoding_decode_t *ctx, bool is_be,
}
LXB_ENCODING_DECODE_ERROR_END();

+ if (ctx->buffer_used >= ctx->buffer_length) {
+ ctx->u.lead = lead + 0x01;
+
+ return LXB_STATUS_SMALL_BUFFER;
+ }
+
goto lead_state;
}

@@ -1723,6 +1736,13 @@ lxb_encoding_decode_gb18030(lxb_encoding_decode_t *ctx,
}
LXB_ENCODING_DECODE_ERROR_END();

+ if (ctx->buffer_used >= ctx->buffer_length) {
+ ctx->prepend = true;
+ ctx->u.gb18030.first = second;
+
+ return LXB_STATUS_SMALL_BUFFER;
+ }
+
first = second;

goto prepend_first;
@@ -1756,11 +1776,8 @@ lxb_encoding_decode_gb18030(lxb_encoding_decode_t *ctx,
}
LXB_ENCODING_DECODE_ERROR_END();

- LXB_ENCODING_DECODE_APPEND_WO_CHECK(ctx, second);
-
- if (ctx->buffer_used == ctx->buffer_length) {
+ if (ctx->buffer_used >= ctx->buffer_length) {
ctx->prepend = true;
- ctx->have_error = true;

/* First is a fake for trigger */
ctx->u.gb18030.first = 0x01;
@@ -1770,6 +1787,18 @@ lxb_encoding_decode_gb18030(lxb_encoding_decode_t *ctx,
return LXB_STATUS_SMALL_BUFFER;
}

+ LXB_ENCODING_DECODE_APPEND_WO_CHECK(ctx, second);
+
+ if (ctx->buffer_used >= ctx->buffer_length) {
+ ctx->prepend = true;
+
+ ctx->u.gb18030.first = third;
+ ctx->u.gb18030.second = 0x00;
+ ctx->u.gb18030.third = 0x00;
+
+ return LXB_STATUS_SMALL_BUFFER;
+ }
+
first = third;

goto prepend_first;