Wrong error handling in bzread() function that possibly leads to code execution was reported. PHP bug: https://bugs.php.net/bug.php?id=72613
Acknowledgments: Name: Hans Jerry Illikainen
Created bzip2 tracking bugs for this issue: Affects: fedora-all [bug 1358401]
Created php tracking bugs for this issue: Affects: fedora-all [bug 1358404]
Created mingw-bzip2 tracking bugs for this issue: Affects: fedora-all [bug 1358402] Affects: epel-7 [bug 1358403]
References: http://seclists.org/bugtraq/2016/Jul/96
I dont think this is a flaw with bzip2, the documentation (http://www.bzip.org/1.0.5/bzip2-manual-1.0.5.html#bzread) clearly states the following: "BZ2_bzRead will supply len bytes, unless the logical stream end is detected or an error occurs. Because of this, it is possible to detect the stream end by observing when the number of bytes returned is less than the number requested. Nevertheless, this is regarded as inadvisable; you should instead check bzerror after every call and watch out for BZ_STREAM_END." php_bz2iop_read does not do this, rather it exits only when the return from BZ2_bzRead < 1, which seems to be not what the bzip API states.
Upstream patch: http://git.php.net/?p=php-src.git;a=commit;h=f3feddb5b45b5abd93abb1a95044b7e099d51c84 Also notice https://secure.php.net/manual/en/function.bzread.php (comment #2) gives a work around to this, ie check output of bzerrno() after every bzread invocation, and quit if its non-zero.
At first read it seems "return 0;" in case of error (read < 0) could be better, but this is handled in stream wrapper (justread && justread != (size_t)-1). Unbuffered: https://github.com/php/php-src/blob/master/ext/zlib/zlib_fopen_wrapper.c#L47 Buffered: https://github.com/php/php-src/blob/master/main/streams/streams.c#L580
Bad links, I mean for unbuffered: https://github.com/php/php-src/blob/master/main/streams/streams.c#L716
Exploitation Notes: ================== When an attacker uploads a specially-crafted .bz2 archive to a php application, which attempts to extract files from the uploaded archive, it could result in arbitrary code execution. This is because when the bz2 library reports a decompression error code, back to PHP, it does not stop the reading process, which can result in further calls to the decompression code of bz2, this may cause OOB writes which may under certain circumstances result in code execution. However the above can easily be mitigated, by making sure that the PHP code calls bzerrno() after every call to bzread() something like: $fh = bzopen('file.bz2','r'); while(!feof($fh)) { $buffer = bzread($fh); if($buffer === FALSE) die('Read problem'); if(bzerrno($fh) !== 0) die('Compression Problem'); } bzclose($fh); Reference: https://secure.php.net/manual/en/function.bzread.php
This issue has been addressed in the following products: Red Hat Enterprise Linux 7 Via RHSA-2016:2598 https://rhn.redhat.com/errata/RHSA-2016-2598.html
This issue has been addressed in the following products: Red Hat Software Collections for Red Hat Enterprise Linux 6 Red Hat Software Collections for Red Hat Enterprise Linux 6.7 EUS Red Hat Software Collections for Red Hat Enterprise Linux 7 Red Hat Software Collections for Red Hat Enterprise Linux 7.2 EUS Red Hat Software Collections for Red Hat Enterprise Linux 7.3 EUS Via RHSA-2016:2750 https://rhn.redhat.com/errata/RHSA-2016-2750.html