php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #71263 fread() does not report bzip2.decompress errors
Submitted: 2016-01-02 16:01 UTC Modified: 2020-04-17 13:39 UTC
From: salsi at icosaedro dot it Assigned: cmb (profile)
Status: Closed Package: Streams related
PHP Version: Irrelevant OS: Slackware 14.1
Private report: No CVE-ID: None
 [2016-01-02 16:01 UTC] 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"


Patches

Pull Requests

Pull requests:

History

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
   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.
 [2018-08-20 17:37 UTC] cmb@php.net
-Package: Filter related +Package: Streams related
 [2020-04-17 08:35 UTC] cmb@php.net
-Summary: fread() does not detects decoding errors from filter bzip2.decompress +Summary: fread() does not report bzip2.decompress errors
 [2020-04-17 08:35 UTC] 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>
 [2020-04-17 12:13 UTC] 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 13:37 UTC] cmb@php.net
-Summary: fread() does not report bzip2.decompress errors +Summary: fread() does not report decompression errors -Status: Open +Status: Verified -Assigned To: +Assigned To: cmb
 [2020-04-17 13:37 UTC] cmb@php.net
The zlib.inflate filter has the same issue.
 [2020-04-17 13:39 UTC] cmb@php.net
-Summary: fread() does not report decompression errors +Summary: fread() does not report bzip2.decompress errors
 [2020-04-17 13:39 UTC] cmb@php.net
> The zlib.inflate filter has the same issue.

But that has already reported as bug #71417.
 [2020-04-20 12:22 UTC] cmb@php.net
Automatic comment on behalf of cmbecker69@gmx.de
Revision: http://git.php.net/?p=php-src.git;a=commit;h=d757be640f5105b8542b781ce93804af494229a8
Log: Fix #71263: fread() does not report bzip2.decompress errors
 [2020-04-20 12:22 UTC] cmb@php.net
-Status: Verified +Status: Closed
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 16:01:28 2024 UTC