From 8e8b5df9024e7b290801ee58303c6719fb94b3b8 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 31 Jan 2025 20:03:25 +0100 Subject: [PATCH] Fix GH-17650: realloc with size 0 in user_filters.c If the returned buffer string is of length 0, then a realloc can happen with length 0. However, the behaviour is implementation-defined. From 7.20.3.1 of C11 spec: > If the size of the space requested is zero, the behavior is > implementation-defined: either a null pointer is returned, > or the behavior is as if the size were some nonzero value, > except that the returned pointer shall not be used to access an object This is problematic for the test case on my system as it returns NULL, causing a memleak and later using it in memcpy causing UB. The bucket code is not prepared to handle a NULL pointer. To solve this, we use MAX to clamp the size to 1 at the least. --- ext/standard/tests/streams/gh17650.phpt | 33 +++++++++++++++++++++++++ ext/standard/user_filters.c | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 ext/standard/tests/streams/gh17650.phpt diff --git a/ext/standard/tests/streams/gh17650.phpt b/ext/standard/tests/streams/gh17650.phpt new file mode 100644 index 0000000000000..8f1faefae2805 --- /dev/null +++ b/ext/standard/tests/streams/gh17650.phpt @@ -0,0 +1,33 @@ +--TEST-- +GH-17650 (realloc with size 0 in user_filters.c) +--FILE-- +data = ''; + $consumed += strlen($bucket->data); + stream_bucket_append($out, $bucket); + } + return PSFS_PASS_ON; + } +} + +stream_filter_register('testfilter','testfilter'); + +$text = "Hello There!"; + +$fp = fopen('php://memory', 'w+'); +fwrite($fp, $text); + +rewind($fp); +stream_filter_append($fp, 'testfilter', STREAM_FILTER_READ, 'testuserfilter'); + +while (fgets($fp)); + +fclose($fp); + +echo "Done\n"; +?> +--EXPECT-- +Done diff --git a/ext/standard/user_filters.c b/ext/standard/user_filters.c index 737237f6630cd..acef5146fa25e 100644 --- a/ext/standard/user_filters.c +++ b/ext/standard/user_filters.c @@ -398,7 +398,7 @@ static void php_stream_bucket_attach(int append, INTERNAL_FUNCTION_PARAMETERS) bucket = php_stream_bucket_make_writeable(bucket); } if (bucket->buflen != Z_STRLEN_P(pzdata)) { - bucket->buf = perealloc(bucket->buf, Z_STRLEN_P(pzdata), bucket->is_persistent); + bucket->buf = perealloc(bucket->buf, MAX(Z_STRLEN_P(pzdata), 1), bucket->is_persistent); bucket->buflen = Z_STRLEN_P(pzdata); } memcpy(bucket->buf, Z_STRVAL_P(pzdata), bucket->buflen);