Web lists-archives.com

[PHP] Re: General file I/O reliability




On 04.01.2016 at 00:37 Umberto Salsi wrote:

> I'm desperately trying to build a reliable stream bzip2 decompressor, but
> until now without much success. The problem is how to detect deconding
> errors, which seem to be impossible (more follows).
> 
> In the meanwhile, I discovered several issues I was not aware of and
> that I wouls share with you, with the premise that all the samples of
> code below are run in a very safe environement where even the smallest
> E_NOTICE causes an exception:
> 
>     error_reporting(-1);
>     ini_set("track_errors", "1");
> 
> 
>     function my_error_handler($errno, $message)
>     {
>         throw new ErrorException($message); 
>     }
> 
>     set_error_handler("my_error_handler");
> 
> 
> 1. fread() succeeds reading an unreadable file. While fopen() complains
> immediately if it cannot read a file:
> 
>     fopen("/root/secret.txt", "r");
>     --> E_WARNING: fopen(/root/secret.txt): failed to open
>     stream: Permission denied
> 
> the fread() function seem much more tolerant reading an unreadable file.
> For example, the /proc/self/mem file can be opened, but its first 512
> bytes block cannot be read and causes an error (credits for this trick:
> http://unix.stackexchange.com/a/6302):
> 
>     $ cat /proc/self/mem
>     cat: /proc/self/mem: Input/output error
> 
> Lets try with PHP what happens:
> 
>     $f = fopen("/proc/self/mem", "r");
>     $bytes = fread($f, 1000);
>     echo "bytes="; var_dump($bytes);
>     --> displays bytes=string(0) "", no error whatsoever
> 
> The file seems empty, and no error whatsoever is shown.
> 
> 
> 2. Also the require*() and include*() family of functions seems very
> tolerant:
> 
>     require("/proc/self/mem");
>     echo "read myself!\n";
>     require("/root/secret.php"); # just to exsercise error reporting :-)
>     --> read myself!
>         E_WARNING: require(/root/secret.php): failed to open
>         stream: Permission denied
> 
> The first require() silently ignored. Bad feeling about safety.
> 
> 
> 3. Now back to the original question: BZIP2 stream decoding from a given
> input resource. Lets start creating a corrupted BZIP2 file:
> 
>     $plain = "The quick brown fox jumps over the lazy dog.";
>     $fn = "test.bz2";
>     $compressed = bzcompress($plain);
>     // Set a random byte in the middle of the compressed data
>     $compressed[strlen($compressed) - 15] = 'X';
>     file_put_contents($fn, $compressed);
> 
> Now I create the input resource filtered with the decompressor:
> 
>     $r = fopen($fn, "r");
>     stream_filter_append($r, 'bzip2.decompress', STREAM_FILTER_READ);
> 
> and lets see what come back:
> 
>     do {
>         $s = fread($r, 10);
>         echo "read: "; var_dump($s);
>     } while(! feof($r));
> 
>     --> read: string(0) ""
>         read: string(10) "bthes ohe "
>         read: string(10) "rpujumr.bt"
>         read: string(10) "hes ohe rp"
>         read: string(10) "ujumr.bthe"
>         read: string(3) "s o"
> 
> What?! Why is fread() returning garbage? and why it does not fails with
> some E_WARNING telling me that the file is corrupted?  And what if my
> program blindly processes these "data"?
> 
> 
> Now the big question is: can I trust file access under PHP anymore? If
> yes (and I hope so) how can my applications be made aware when something
> goes wrong?

I suggest that you file respective bug reports (unless that has already
happened).

-- 
Christoph M. Becker


-- 
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php