|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #71263 fread() does not detects decoding errors from filter bzip2.decompress
Submitted: 2016-01-02 16:01 UTC Modified: -
From: salsi at icosaedro dot it Assigned:
Status: Open Package: Filter related
PHP Version: Irrelevant OS: Slackware 14.1
Private report: No CVE-ID:
Have you experienced this issue?
Rate the importance of this bug to you:

 [2016-01-02 16:01 UTC] salsi at icosaedro dot it
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:
// Bug report: bzip2.decompress fails to detect corrupted data.

// Set a safe environment:
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); 


 * 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);


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"


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2016-01-16 00:27 UTC] salsi at icosaedro dot it
Possibly related:

1. require* and include* do not detect input/output error

2. fread() does not detect file access error

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.
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Tue Aug 29 15:01:52 2017 UTC