Skip to content

Commit 1519770

Browse files
committed
Fixed bug #54350
Don't allow calling fclose() on the stream while in the user filter callback. This is basically the same protection as xp_ssl streams use during callback invocations. There are more issues in this general area (e.g. stack overflow on stream_filter_remove), but this addresses freeing the stream during the filter callback invocation at least.
1 parent e5d35a3 commit 1519770

File tree

3 files changed

+32
-0
lines changed

3 files changed

+32
-0
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 7.4.26
44

5+
- Streams:
6+
. Fixed bug #54340 (Memory corruption with user_filter). (Nikita)
57

68
21 Oct 2021, PHP 7.4.25
79

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
--TEST--
2+
Bug #54350: Memory corruption with user_filter
3+
--FILE--
4+
<?php
5+
6+
class user_filter extends php_user_filter {
7+
function filter($in, $out, &$consumed, $closing): int {
8+
while ($bucket = stream_bucket_make_writeable($in)) {
9+
}
10+
fclose($this->stream);
11+
return 0;
12+
}
13+
}
14+
stream_filter_register('user_filter','user_filter');
15+
$fd = fopen('php://memory','w');
16+
$filter = stream_filter_append($fd, 'user_filter');
17+
fwrite($fd, "foo");
18+
19+
?>
20+
--EXPECTF--
21+
Warning: fclose(): 5 is not a valid stream resource in %s on line %d
22+
23+
Warning: fclose(): supplied resource is not a valid stream resource in %s on line %d

ext/standard/user_filters.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ php_stream_filter_status_t userfilter_filter(
172172
return ret;
173173
}
174174

175+
/* Make sure the stream is not closed while the filter callback executes. */
176+
uint32_t orig_no_fclose = stream->flags & PHP_STREAM_FLAG_NO_FCLOSE;
177+
stream->flags |= PHP_STREAM_FLAG_NO_FCLOSE;
178+
175179
if (!zend_hash_str_exists_ind(Z_OBJPROP_P(obj), "stream", sizeof("stream")-1)) {
176180
zval tmp;
177181

@@ -248,6 +252,9 @@ php_stream_filter_status_t userfilter_filter(
248252
zval_ptr_dtor(&args[1]);
249253
zval_ptr_dtor(&args[0]);
250254

255+
stream->flags &= ~PHP_STREAM_FLAG_NO_FCLOSE;
256+
stream->flags |= orig_no_fclose;
257+
251258
return ret;
252259
}
253260

0 commit comments

Comments
 (0)