Bug 1347772 (CVE-2016-4473)

Summary: CVE-2016-4473 php: Invalid free() instead of efree() in phar_extract_file()
Product: [Other] Security Response Reporter: Adam Mariš <amaris>
Component: vulnerabilityAssignee: Red Hat Product Security <security-response-team>
Status: CLOSED ERRATA QA Contact:
Severity: medium Docs Contact:
Priority: medium    
Version: unspecifiedCC: 84560466, abhgupta, dmcphers, hhorak, jialiu, jokerman, jorton, kseifried, lmeyer, mmccomas, rcollet, security-response-team, tiwillia
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: php 5.6.23 Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2016-06-23 14:22:04 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 1347776    

Description Adam Mariš 2016-06-17 15:21:10 UTC
It was reported that invalid free may occur under certain conditions when processing phar-compatible archives in php 7.0.7 and 5.6.22.

Vulnerable code (php-7.0.7/ext/phar/phar_object.c):

| 4063 static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *dest, int dest_len, char **error) /* {{{ */
| 4064 {
| ....
| 4071 cwd_state new_state;
| ....
| 4084 new_state.cwd = (char*)emalloc(2); // (1)
| 4085 new_state.cwd[0] = DEFAULT_SLASH;
| 4086 new_state.cwd[1] = '\0';
| 4087 new_state.cwd_length = 1;
| 4088 if (virtual_file_ex(&new_state, entry->filename, NULL, CWD_EXPAND) != 0 ||
| 4089 new_state.cwd_length <= 1) {
| ....
| 4099 }
| ....
| 4163
| 4164 if (FAILURE == php_stream_stat_path(fullpath, &ssb)) {
| 4165 if (entry->is_dir) {
| 4166 if (!php_stream_mkdir(fullpath, entry->flags & PHAR_ENT_PERM_MASK, PHP_STREAM_MKDIR_RECURSIVE, NULL)) { // (2)
| ....
| 4169 free(new_state.cwd);
| ....
| 4171 }
| 4172 } else {
| 4173 if (!php_stream_mkdir(fullpath, 0777, PHP_STREAM_MKDIR_RECURSIVE, NULL)) { // (3)
| ....
| 4176 free(new_state.cwd);
| ....
| 4178 }
| 4179 }
| 4180 }
| ....
| 4246 }

`new_state.cwd' is initially allocated through the internal zend allocator in (1) and is later reallocated as the file path is resolved.

In `virtual_file_ex' (php-7.0.7/Zend/zend_virtual_cwd.c):

| 1178 CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func verify_path, int use_realpath) /* {{{ */
| 1179 {
| ....
| 1336 if (verify_path) {
| ....
| 1342 tmp = erealloc(state->cwd, state->cwd_length+1);
| ....
| 1349 state->cwd = (char *) tmp;
| 1350
| 1351 memcpy(state->cwd, resolved_path, state->cwd_length+1);
| ....
| 1360 } else {
| ....
| 1362 tmp = erealloc(state->cwd, state->cwd_length+1);
| ....
| 1369 state->cwd = (char *) tmp;
| 1370
| 1371 memcpy(state->cwd, resolved_path, state->cwd_length+1);
| ....
| 1373 }
| ....
| 1379 }

If `php_stream_mkdir' fails in (2) or (3), `cwd' is freed by the underlying libc allocator. If `cwd' is user-controlled, this could potentially result in code execution.

Comment 1 Adam Mariš 2016-06-17 15:21:19 UTC
Acknowledgments:

Name: Hans Jerry Illikainen

Comment 3 Tomas Hoger 2016-06-23 14:22:04 UTC
Affected code was introduced as part of the fix for CVE-2015-6833 (bug 1283702), which was applied upstream in versions 5.4.44, 5.5.28, and 5.6.12.  However, this problem only affects 5.6 versions, which required this additional fix:

https://git.php.net/?p=php-src.git;a=commitdiff;h=eb7ba73079b73ca4ef91307ae1ef30b43468717b

This commit failed to change all free(new_state.cwd) to efree(new_state.cwd).

This issue is triggered when extracting Zip-based Phar archive to a directory that already contains a file of the same name as a directory to be extracted.

Phar files are distribution format for PHP applications (similar to Java Jar format) and their content is typically executed on the server.  Malicious Phar archive can therefore execute code on the system without exploiting any parsing issues.

If Phar extension is not used, it can be disabled by commenting out the following line:

  extension=phar.so

in phar.ini to prevent loading of the extension.

Comment 5 errata-xmlrpc 2016-11-15 11:41:06 UTC
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