Skip to content

Commit 2ad8c64

Browse files
Fix GH-20370: forbid user stream filters to violate typed property constraints
1 parent 55f7303 commit 2ad8c64

File tree

4 files changed

+87
-8
lines changed

4 files changed

+87
-8
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ PHP NEWS
8181
- Streams:
8282
. Fixed bug GH-19798: XP_SOCKET XP_SSL (Socket stream modules): Incorrect
8383
condition for Win32/Win64. (Jakub Zelenka)
84+
. Fixed bug GH-20370 (User stream filters could violate typed property
85+
constraints). (alexandre-daubois)
8486

8587
- Tidy:
8688
. Fixed GH-19021 (improved tidyOptGetCategory detection).
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--TEST--
2+
GH-20370 (User filters should respect typed properties)
3+
--FILE--
4+
<?php
5+
6+
class pass_filter
7+
{
8+
public $filtername;
9+
public $params;
10+
public int $stream = 1;
11+
12+
function filter($in, $out, &$consumed, $closing): int
13+
{
14+
while ($bucket = stream_bucket_make_writeable($in)) {
15+
$consumed += $bucket->datalen;
16+
stream_bucket_append($out, $bucket);
17+
}
18+
return PSFS_PASS_ON;
19+
}
20+
}
21+
22+
stream_filter_register("pass", "pass_filter");
23+
$fp = fopen("php://memory", "w");
24+
stream_filter_append($fp, "pass");
25+
26+
try {
27+
fwrite($fp, "data");
28+
} catch (TypeError $e) {
29+
echo "TypeError: Cannot assign resource to typed property\n";
30+
}
31+
32+
?>
33+
--EXPECTF--
34+
Warning: fwrite(): Unprocessed filter buckets remaining on input brigade in %s on line %d
35+
TypeError: Cannot assign resource to typed property
36+
37+
Fatal error: Uncaught TypeError: Cannot assign resource to property pass_filter::$stream of type int in %s
38+
Stack trace:
39+
#0 {main}
40+
thrown in %s
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--TEST--
2+
GH-20370 (User filters should not create stream property if not declared)
3+
--FILE--
4+
<?php
5+
6+
class pass_filter
7+
{
8+
public $filtername;
9+
public $params;
10+
11+
function filter($in, $out, &$consumed, $closing): int
12+
{
13+
while ($bucket = stream_bucket_make_writeable($in)) {
14+
$consumed += $bucket->datalen;
15+
stream_bucket_append($out, $bucket);
16+
}
17+
18+
var_dump(property_exists($this, 'stream'));
19+
return PSFS_PASS_ON;
20+
}
21+
}
22+
23+
stream_filter_register("pass", "pass_filter");
24+
$fp = fopen("php://memory", "w");
25+
stream_filter_append($fp, "pass");
26+
fwrite($fp, "data");
27+
rewind($fp);
28+
echo fread($fp, 1024) . "\n";
29+
30+
?>
31+
--EXPECT--
32+
bool(false)
33+
bool(false)
34+
bool(false)
35+
bool(false)
36+
data
37+
bool(false)

ext/standard/user_filters.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,12 @@ php_stream_filter_status_t userfilter_filter(
147147
uint32_t orig_no_fclose = stream->flags & PHP_STREAM_FLAG_NO_FCLOSE;
148148
stream->flags |= PHP_STREAM_FLAG_NO_FCLOSE;
149149

150-
zval *stream_prop = zend_hash_str_find_ind(Z_OBJPROP_P(obj), "stream", sizeof("stream")-1);
151-
if (stream_prop) {
152-
/* Give the userfilter class a hook back to the stream */
153-
zval_ptr_dtor(stream_prop);
154-
php_stream_to_zval(stream, stream_prop);
155-
Z_ADDREF_P(stream_prop);
150+
/* Give the userfilter class a hook back to the stream */
151+
zend_property_info *prop_info = zend_hash_str_find_ptr(&Z_OBJCE_P(obj)->properties_info, "stream", sizeof("stream")-1);
152+
if (prop_info) {
153+
zval stream_zval;
154+
php_stream_to_zval(stream, &stream_zval);
155+
zend_update_property(Z_OBJCE_P(obj), Z_OBJ_P(obj), "stream", sizeof("stream")-1, &stream_zval);
156156
}
157157

158158
ZVAL_STRINGL(&func_name, "filter", sizeof("filter")-1);
@@ -196,8 +196,8 @@ php_stream_filter_status_t userfilter_filter(
196196
/* filter resources are cleaned up by the stream destructor,
197197
* keeping a reference to the stream resource here would prevent it
198198
* from being destroyed properly */
199-
if (stream_prop) {
200-
convert_to_null(stream_prop);
199+
if (prop_info) {
200+
zend_update_property_null(Z_OBJCE_P(obj), Z_OBJ_P(obj), "stream", sizeof("stream")-1);
201201
}
202202

203203
zval_ptr_dtor(&args[3]);

0 commit comments

Comments
 (0)