Skip to content

Commit d5f84c7

Browse files
EdmondDantesLamentXU123
authored andcommitted
Fix use-after-free when removing a failing zlib.inflate filter (#24176)
Corrupt input makes zlib.inflate raise an E_NOTICE. An error handler can remove the filter and free its state, so resetting the input pointers after the notice writes to freed memory. Release the input bucket and reset the filter state before raising the notice, then return without accessing the filter again. Add regression coverage for error handlers that remove both write and read filters. Closing the stream itself from an error handler is outside this fix and requires protection around the filter chain walk. Closes #24176
1 parent 06be15d commit d5f84c7

3 files changed

Lines changed: 36 additions & 1 deletion

File tree

‎NEWS‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ PHP NEWS
4949
is called from a progress or cancel callback during close().
5050
(Ilia Alshanetsky)
5151

52+
- Zlib:
53+
. Fixed use-after-free when an error handler removes a failing zlib.inflate
54+
filter (GH-24176). (Edmond)
55+
5256
22 Oct 2026, PHP 8.4.27
5357

5458
- BCMath:
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
zlib.inflate filter removed by the error handler of its own notice
3+
--EXTENSIONS--
4+
zlib
5+
--FILE--
6+
<?php
7+
$fp = fopen('php://memory', 'w+');
8+
$filter = stream_filter_append($fp, 'zlib.inflate', STREAM_FILTER_WRITE);
9+
set_error_handler(function (int $errno, string $errstr) use (&$filter) {
10+
echo $errstr, "\n";
11+
var_dump(stream_filter_remove($filter));
12+
return true;
13+
});
14+
var_dump(fwrite($fp, "\xff\xff\xff\xff"));
15+
16+
$fp = fopen('php://memory', 'w+');
17+
fwrite($fp, "\xff\xff\xff\xff");
18+
rewind($fp);
19+
$filter = stream_filter_append($fp, 'zlib.inflate', STREAM_FILTER_READ);
20+
var_dump(fread($fp, 10));
21+
echo "Done\n";
22+
?>
23+
--EXPECT--
24+
fwrite(): zlib: data error
25+
bool(true)
26+
bool(false)
27+
fread(): zlib: data error
28+
bool(true)
29+
bool(false)
30+
Done

‎ext/zlib/zlib_filter.c‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,12 @@ static php_stream_filter_status_t php_zlib_inflate_filter(
9090
exit_status = PSFS_PASS_ON;
9191
} else if (status != Z_OK && status != Z_BUF_ERROR) {
9292
/* Something bad happened */
93-
php_error_docref(NULL, E_NOTICE, "zlib: %s", zError(status));
9493
php_stream_bucket_delref(bucket);
9594
/* reset these because despite the error the filter may be used again */
9695
data->strm.next_in = data->inbuf;
9796
data->strm.avail_in = 0;
97+
/* Last: an error handler may remove this filter and free data. */
98+
php_error_docref(NULL, E_NOTICE, "zlib: %s", zError(status));
9899
return PSFS_ERR_FATAL;
99100
}
100101
desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */

0 commit comments

Comments
 (0)