Edit report at https://bugs.php.net/bug.php?id=71263&edit=1
ID: 71263
Updated by: cmb@php.net
Reported by: salsi at icosaedro dot it
-Summary: fread() does not report bzip2.decompress errors
+Summary: fread() does not report decompression errors
-Status: Open
+Status: Verified
Type: Bug
Package: Streams related
Operating System: Slackware 14.1
PHP Version: Irrelevant
-Assigned To:
+Assigned To: cmb
Block user comment: N
Private report: N
New Comment:
The zlib.inflate filter has the same issue.
Previous Comments:
------------------------------------------------------------------------
[2020-04-17 12:13:03] cmb@php.net
The following pull request has been associated:
Patch Name: Fix #71263: fread() does not report bzip2.decompress errors
On GitHub: https://github.com/php/php-src/pull/5406
Patch: https://github.com/php/php-src/pull/5406.patch
------------------------------------------------------------------------
[2020-04-17 08:35:41] cmb@php.net
As of PHP 7.4.0, bzip2.decompress errors already cause fread() to
return false, due to a more general fix of the stream behavior[1].
This is still a silent failure, though.
[1] <https://www.php.net/manual/en/migration74.incompatible.php#migration74.incompatible.core.fread-fwrite>
------------------------------------------------------------------------
[2016-01-16 00:27:04] salsi at icosaedro dot it
Possibly related:
1. require* and include* do not detect input/output error
https://bugs.php.net/bug.php?id=71385
2. fread() does not detect file access error
https://bugs.php.net/bug.php?id=71384
In all these case it seems I/O errors fails to propagate through the chain of the stream functions,
either returning empty string or garbage, with severe safety and security risks both for front-end
and back-end processes.
------------------------------------------------------------------------
[2016-01-02 16:01:34] salsi at icosaedro dot it
Description:
------------
When the bzip2.decompress filter is applied to a stream, the fread() function does not detect
decoding errors on a corrupted file and keeps instead returning the empty string or garbage. The
following script illustrates 3 distinct cases.
Checking what really happens inside the php_bz2_decompress_filter() function, in 2 of the 3 cases
this function correctly detects an error in the corrupted file and returns PSFS_ERR_FATAL, but in
the script the fread() function always succeeds.
In one case the php_bz2_decompress_filter() function does not detect anything, but fread() succeeds
and returns the empty string.
In my opinion, if a decoding error is detected it is just like reading from a damaged file and
fread() should return FALSE and triggering E_WARNING (which this script would map to
ErrorException).
I've tested on PHP 7.0-dev, but I don't think the PHP version does really matters here.
Unsure if this bug is in some way related to #17651.
Test script:
---------------
<?php
// Bug report: bzip2.decompress fails to detect corrupted data.
// Set a safe environment:
error_reporting(-1);
ini_set("track_errors", "1");
/**
* Maps errors to ErrorException.
* @access private
* @param int $errno
* @param string $message
* @return boolean
* @throws ErrorException
*/
function my_error_handler($errno, $message /*, $filename, $lineno, $context */)
{
throw new ErrorException($message);
}
set_error_handler("my_error_handler");
/**
* Testing reading corrupted BZIP2 file using bzip2.decompress filter.
* @throws ErrorException
*/
function main()
{
$plain = "The quick brown fox jumps over the lazy dog.";
$fn = "test.bz2";
$compressed = (string) bzcompress($plain);
echo "Compressed len = ", strlen($compressed), "\n";
// Set a random byte in the middle of the compressed data
// --> php_bz2_decompress_filter() detects fatal error
// --> fread() displays empty string then garbage, no errors detected:
$compressed[strlen($compressed) - 15] = 'X';
// Truncate the compressed data
// --> php_bz2_decompress_filter() does not detect errors,
// --> fread() displays the empty string:
// $compressed = substr($compressed, 0, strlen($compressed) - 20);
// Corrupted final CRC
// --> php_bz2_decompress_filter() detects fatal error
// --> fread() displays an empty string, then the correct plain text, no error detected:
// $compressed[strlen($compressed)-2] = 'X';
file_put_contents($fn, $compressed);
$r = fopen($fn, "r");
stream_filter_append($r, 'bzip2.decompress', STREAM_FILTER_READ);
while( ! feof($r) ){
$s = fread($r, 100);
echo "read: "; var_dump($s);
}
fclose($r);
unlink($fn);
}
main();
?>
Expected result:
----------------
Compressed len = 81
Fatal error: Uncaught ErrorException: fread() I/O error in /home/salsi/BZIP2-bug-report.php:24
(or possibly a more descriptive error message, although it might be difficult to do due to the
limitations of the filter interface)
Actual result:
--------------
Compressed len = 81
read: string(0) ""
read: string(43) "bthes ohe rpujumr.bthes ohe rpujumr.bthes o"
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=71263&edit=1