A multibyte lead byte at the end of a multipart field name made the
scan advance by the full character width past the terminating NUL,
reading out of bounds. Advance byte by byte and stop at the
terminator in both advance sites, as php_mb_rfc1867_substring_conf()
already does.
Closes GH-24498
- Replace bailout on OOM with UnwindExit
- Properly reset various globals that may be accessed during startup
Fix GHSA-w8hw-w9fx-j79w (CVE-2026-109618)
Fix GHSA-6wmf-4rv5-p3rp (CVE-2026-109619)
Co-authored-by: Ilija Tovilo <ilija.tovilo@me.com>
Co-authored-by: Jakub Zelenka <bukka@php.net>
Co-authored-by: Nora Dossche <7771979+ndossche@users.noreply.github.com>
Co-authored-by: Nicolas Grekas <nicolas.grekas@gmail.com>
offset_to_pointer_utf8() walks the haystack using the UTF-8 mblen table.
For a truncated multibyte sequence, the lead byte's table entry can exceed
the remaining bytes and leave the search start pointer past the end.
Passing that pointer to zend_memnstr() triggers an assertion in debug
builds and an out-of-bounds read in release builds, producing bogus
offsets or a crash for sufficiently long haystacks.
Clamp the pointer to the end of the string, as mb_str_split() already does
for the same table walk. Add regression coverage for forward and reverse
searches, negative offsets, and offsets beyond the haystack.
Fixes GH-23106.
Closes#23107
mb_find_strpos() converts the haystack and needle to UTF-8 and does the length and offset math on the converted strings.
The negative-offset branch computed the needle length from the raw needle instead of needle_u8.
mb_fast_strlen_utf8() reads those bytes as UTF-8, so the count is wrong whenever they do not decode one to one.
A byte in 0x80-0xBF (ISO-8859-1) undercounts, and a wider encoding such as an ASCII needle in UTF-16 overcounts, so the reverse-search window is shifted.
Use needle_u8, the converted needle the rest of the branch already searches with.
A header field name with no value (input ending at the colon) leaves
fld_name allocated but unreleased, since the cleanup blocks only fire
when both fld_name and fld_val are set. Release the dangling fld_name in
both the loop-body and end-of-input branches.
Closes GH-22254
There are several issues with this macro:
- It is incorrectly named: It's not an empty default case. It's an unreachable
default case.
- It is hiding control flow in its definition, which can be confusing for
humans and tools (such as Coccinelle) alike, because it looks like it would
be a statement that belongs to the "current" case rather than opening a new
one.
Since this macro is exactly as long as explicitly spelling out its definition
(excluding the useless `break;`), it is not even making the code any more
succinct.
This avoids a crash in cases where the list of candidate encodings is so huge
that alloca would fail. Such crashes have been observed when the list of
encodings was larger than around 208,000 entries.
Thanks to the GitHub user vi3tL0u1s (Viet Hoang Luu) for reporting this issue.
The MacJapanese legacy text encoding has a very unusual property; it is possible for a string
to encode more codepoints than it has bytes. In some corner cases, this resulted in a situation
where the implementation code for mb_substr() would allocate a buffer of size -1. As you can
probably imagine, that doesn't end well.
Fixes GH-20832.