[php-src] Issue #24048: phar: missing NULL check of php_stream_filter_create() result for "bzip2.compress" in phar_tar_flush() and phar_flush()
| From: | ushevchenko | Date: | Thu, 01 Oct 2026 13:20:20 +0000 |
| Subject: | [php-src] Issue #24048: phar: missing NULL check of php_stream_filter_create() result for "bzip2.compress" in phar_tar_flush() and phar_flush() | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-252868@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/24048
Author: ushevchenko
### Description
In phar_tar_flush() in ext/phar/tar.c the bzip2 branch uses the result of php_stream_filter_create()
without checking it for NULL:
} else if (phar->flags & PHAR_FILE_COMPRESSED_BZ2) {
php_stream_filter *filter;
filter = php_stream_filter_create("bzip2.compress", NULL,
php_stream_is_persistent(phar->fp));
php_stream_filter_append(&phar->fp->writefilters, filter);
php_stream_copy_to_stream_ex(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
php_stream_filter_flush(filter, 1);
php_stream_filter_remove(filter, 1);
The gzip branch of the same function handles a failed php_stream_filter_create() with
if
(!filter) (it copies the contents uncompressed, sets error and returns EOF), the
bzip2 branch does not.
So the code contains a path where filter is NULL and is passed to php_stream_filter_append(),
php_stream_filter_flush() and php_stream_filter_remove(), which dereference it. The same unchecked
pattern exists in phar_flush() in ext/phar/phar.c.
Reachability. I did not reproduce a crash; this report is based on reading the code.
php_stream_filter_create() returns NULL if no factory is found or the factory itself returns NULL.
For "bzip2.compress" with NULL parameters, php_bz2_filter_create() in ext/bz2/bz2_filter.c
returns NULL only if BZ2_bzCompressInit() fails. It is called with the default values
(PHP_BZ2_FILTER_DEFAULT_BLOCKSIZE, PHP_BZ2_FILTER_DEFAULT_WORKFACTOR), which are inside the valid
ranges, and the allocator used by the filter (safe_pemalloc) does not return NULL. The NULL path
therefore looks unreachable today. The static analyzer reports that the result of
php_stream_filter_create() is checked in 15 of 16 calls, so this is a robustness and consistency
issue rather than a known crash.
**Suggested fix**
Handle a NULL filter in the bzip2 branch the same way as in the gzip branch (copy the contents
uncompressed, close newfile, set the error message, return EOF), and add an equivalent check in
phar_flush().
Found by Linux Verification Center (https://portal.linuxtesting.ru) using SVACE.
Author U. Shevchenko.
### PHP Version
```plain
8.3.31 (static analysis of the source, not run); the same code is present in master
```
### Operating System
N/A (static analysis)