diff options
author | Remi Collet <fedora@famillecollet.com> | 2016-07-22 19:29:20 +0200 |
---|---|---|
committer | Remi Collet <fedora@famillecollet.com> | 2016-07-22 19:29:20 +0200 |
commit | 2f649ee4cbea50aaf88ae480ecfe36651dd135a2 (patch) | |
tree | a354b0289ff36de74a82652f9946413b6917dd95 | |
parent | d3a4c0e1202c51c100fe28a60ed9beab1918de91 (diff) |
PHP 5.4.45 with security fix from 5.5.38
-rw-r--r-- | bug69975.patch | 89 | ||||
-rw-r--r-- | bug70480.patch | 29 | ||||
-rw-r--r-- | bug72479.patch | 408 | ||||
-rw-r--r-- | bug72513.patch | 48 | ||||
-rw-r--r-- | bug72519.patch | 54 | ||||
-rw-r--r-- | bug72520.patch | 78 | ||||
-rw-r--r-- | bug72533.patch | 80 | ||||
-rw-r--r-- | bug72562.patch | 73 | ||||
-rw-r--r-- | bug72573.patch | 464 | ||||
-rw-r--r-- | bug72603.patch | 76 | ||||
-rw-r--r-- | bug72606.patch | 152 | ||||
-rw-r--r-- | bug72613.patch | 281 | ||||
-rw-r--r-- | bug72618.patch | 110 | ||||
-rw-r--r-- | failed.txt | 7 | ||||
-rw-r--r-- | php54.spec | 45 |
15 files changed, 1991 insertions, 3 deletions
diff --git a/bug69975.patch b/bug69975.patch new file mode 100644 index 0000000..4aafb17 --- /dev/null +++ b/bug69975.patch @@ -0,0 +1,89 @@ +Adapted for 5.4, by Remi Collet, from: + + +From 82637e818776d4fe778fb1dbac26eeece02e900c Mon Sep 17 00:00:00 2001 +From: "Christoph M. Becker" <cmb@php.net> +Date: Fri, 3 Jul 2015 00:04:50 +0200 +Subject: [PATCH] Fix #69975: PHP segfaults when accessing nvarchar(max) + defined columns + +The SQL Server Native Client 11.0 and maybe other ODBC drivers report +NVARCHAR(MAX) columns as SQL_WVARCHAR with size 0. This causes too small a +buffer to be emalloc'd, likely causing a segfault in the following. As we don't +know the real size of the column data, we treat such colums as +SQL_WLONGVARCHAR. + +The related bug #67437 suggests that some drivers report a size of ~4GB. It is +not certain that this is really the case (there might be some integer overflow +involved, and anyway, there has been no feedback), so we do not cater for this +now. However, it would not be hard to treat all sizes above a certain threshold +in a similar way, i.e. as SQL_WLONGVARCHAR. + +(cherry picked from commit 16db4d1462bf3eacb93c0cd940f799160a284b24) +(cherry picked from commit 344ff5dd4c538eaebea075f7705321f8b86d0b47) +--- + ext/odbc/php_odbc.c | 7 +++++++ + ext/odbc/tests/bug69975.phpt | 32 ++++++++++++++++++++++++++++++++ + 2 files changed, 39 insertions(+) + create mode 100644 ext/odbc/tests/bug69975.phpt + +diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c +index ddfbc4e..1d70b7f 100644 +--- a/ext/odbc/php_odbc.c ++++ b/ext/odbc/php_odbc.c +@@ -1005,6 +1005,14 @@ int odbc_bindcols(odbc_result *result TS + default: + rc = SQLColAttributes(result->stmt, (SQLUSMALLINT)(i+1), colfieldid, + NULL, 0, NULL, &displaysize); ++#if defined(ODBCVER) && (ODBCVER >= 0x0300) ++ /* Workaround for drivers that report NVARCHAR(MAX) columns as SQL_WVARCHAR with size 0 (bug #69975) */ ++ if (result->values[i].coltype == SQL_WVARCHAR && displaysize == 0) { ++ result->values[i].coltype = SQL_WLONGVARCHAR; ++ result->values[i].value = NULL; ++ break; ++ } ++#endif + /* Workaround for Oracle ODBC Driver bug (#50162) when fetching TIMESTAMP column */ + if (result->values[i].coltype == SQL_TIMESTAMP) { + displaysize += 3; +diff --git a/ext/odbc/tests/bug69975.phpt b/ext/odbc/tests/bug69975.phpt +new file mode 100644 +index 0000000..eca7564 +--- /dev/null ++++ b/ext/odbc/tests/bug69975.phpt +@@ -0,0 +1,32 @@ ++--TEST-- ++Bug #69975 (PHP segfaults when accessing nvarchar(max) defined columns) ++--SKIPIF-- ++<?php include 'skipif.inc'; ?> ++--FILE-- ++<?php ++include 'config.inc'; ++ ++$conn = odbc_connect($dsn, $user, $pass); ++@odbc_exec($conn, 'CREATE DATABASE odbcTEST'); ++odbc_exec($conn, 'CREATE TABLE FOO (ID INT, VARCHAR_COL NVARCHAR(MAX))'); ++odbc_exec($conn, "INSERT INTO FOO VALUES (1, 'foo')"); ++ ++$result = odbc_exec($conn, "SELECT VARCHAR_COL FROM FOO"); ++var_dump(odbc_fetch_array($result)); ++ ++echo "ready"; ++?> ++--EXPECT-- ++array(1) { ++ ["VARCHAR_COL"]=> ++ string(3) "foo" ++} ++ready ++--CLEAN-- ++<?php ++include 'config.inc'; ++ ++$conn = odbc_connect($dsn, $user, $pass); ++odbc_exec($conn, 'DROP TABLE FOO'); ++odbc_exec($conn, 'DROP DATABASE odbcTEST'); ++?> +-- +2.1.4 + diff --git a/bug70480.patch b/bug70480.patch new file mode 100644 index 0000000..e39ea89 --- /dev/null +++ b/bug70480.patch @@ -0,0 +1,29 @@ +Adapted for 5.4, by Remi Collet, from: + + +From e1ba58f068f4bfc8ced75bb017cd31d8beddf3c2 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Mon, 28 Sep 2015 11:31:14 -0700 +Subject: [PATCH] Fix bug #70480 (php_url_parse_ex() buffer overflow read) + +(cherry picked from commit 629e4da7cc8b174acdeab84969cbfc606a019b31) +--- + ext/standard/url.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ext/standard/url.c b/ext/standard/url.c +index fc3f080..b5739f0 100644 +--- a/ext/standard/url.c ++++ b/ext/standard/url.c +@@ -321,7 +321,7 @@ PHPAPI php_url *php_url_parse_ex(char co + nohost: + + if ((p = memchr(s, '?', (ue - s)))) { +- pp = strchr(s, '#'); ++ pp = memchr(s, '#', (ue - s)); + + if (pp && pp < p) { + if (pp - s) { +-- +2.1.4 + diff --git a/bug72479.patch b/bug72479.patch new file mode 100644 index 0000000..6d459be --- /dev/null +++ b/bug72479.patch @@ -0,0 +1,408 @@ +From cab1c3b3708eead315e033359d07049b23b147a3 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Sun, 26 Jun 2016 17:52:09 -0700 +Subject: [PATCH] Fixed bug #72479 - same as #72434 + +--- + ext/snmp/snmp.c | 89 ++++++++++++++++++++++++-------------------- + ext/snmp/tests/bug72479.phpt | 35 +++++++++++++++++ + 2 files changed, 84 insertions(+), 40 deletions(-) + create mode 100644 ext/snmp/tests/bug72479.phpt + +diff --git a/ext/snmp/snmp.c b/ext/snmp/snmp.c +index 6c1da4c..e1161c7 100644 +--- a/ext/snmp/snmp.c ++++ b/ext/snmp/snmp.c +@@ -475,7 +475,7 @@ static void php_snmp_session_destructor(zend_rsrc_list_entry *rsrc TSRMLS_DC) + static void php_snmp_object_free_storage(void *object TSRMLS_DC) + { + php_snmp_object *intern = (php_snmp_object *)object; +- ++ + if (!intern) { + return; + } +@@ -483,7 +483,7 @@ static void php_snmp_object_free_storage(void *object TSRMLS_DC) + netsnmp_session_free(&(intern->session)); + + zend_object_std_dtor(&intern->zo TSRMLS_CC); +- ++ + efree(intern); + } + +@@ -503,7 +503,7 @@ static zend_object_value php_snmp_object_new(zend_class_entry *class_type TSRMLS + retval.handlers = (zend_object_handlers *) &php_snmp_object_handlers; + + return retval; +- ++ + } + + /* {{{ php_snmp_error +@@ -556,7 +556,7 @@ static void php_snmp_getvalue(struct variable_list *vars, zval *snmpval TSRMLS_D + char *dbuf = (char *)NULL; + int buflen = sizeof(sbuf) - 1; + int val_len = vars->val_len; +- ++ + /* use emalloc() for large values, use static array otherwize */ + + /* There is no way to know the size of buffer snprint_value() needs in order to print a value there. +@@ -702,7 +702,7 @@ static void php_snmp_getvalue(struct variable_list *vars, zval *snmpval TSRMLS_D + * SNMP object fetcher/setter for all SNMP versions + * + */ +-static void php_snmp_internal(INTERNAL_FUNCTION_PARAMETERS, int st, ++static void php_snmp_internal(INTERNAL_FUNCTION_PARAMETERS, int st, + struct snmp_session *session, + struct objid_query *objid_query) + { +@@ -721,7 +721,7 @@ static void php_snmp_internal(INTERNAL_FUNCTION_PARAMETERS, int st, + + /* we start with retval=FALSE. If any actual data is acquired, retval will be set to appropriate type */ + RETVAL_FALSE; +- ++ + /* reset errno and errstr */ + php_snmp_error(getThis(), NULL TSRMLS_CC, PHP_SNMP_ERRNO_NOERROR, ""); + +@@ -805,8 +805,8 @@ retry: + } + for (vars = response->variables; vars; vars = vars->next_variable) { + /* do not output errors as values */ +- if ( vars->type == SNMP_ENDOFMIBVIEW || +- vars->type == SNMP_NOSUCHOBJECT || ++ if ( vars->type == SNMP_ENDOFMIBVIEW || ++ vars->type == SNMP_NOSUCHOBJECT || + vars->type == SNMP_NOSUCHINSTANCE ) { + if ((st & SNMP_CMD_WALK) && Z_TYPE_P(return_value) == IS_ARRAY) { + break; +@@ -816,8 +816,8 @@ retry: + php_snmp_error(getThis(), NULL TSRMLS_CC, PHP_SNMP_ERRNO_ERROR_IN_REPLY, "Error in packet at '%s': %s", buf, buf2); + continue; + } +- +- if ((st & SNMP_CMD_WALK) && ++ ++ if ((st & SNMP_CMD_WALK) && + (vars->name_length < rootlen || memcmp(root, vars->name, rootlen * sizeof(oid)))) { /* not part of this subtree */ + if (Z_TYPE_P(return_value) == IS_ARRAY) { /* some records are fetched already, shut down further lookup */ + keepwalking = 0; +@@ -1101,7 +1101,7 @@ static int php_snmp_parse_oid(zval *object, int st, struct objid_query *objid_qu + efree(objid_query->vars); + return FALSE; + } +- } else { ++ } else { + memmove((char *)objid_query->vars[0].name, (char *)objid_mib, sizeof(objid_mib)); + objid_query->vars[0].name_length = sizeof(objid_mib) / sizeof(oid); + } +@@ -1437,7 +1437,7 @@ static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version) + int session_less_mode = (getThis() == NULL); + php_snmp_object *snmp_object; + php_snmp_object glob_snmp_object; +- ++ + objid_query.max_repetitions = -1; + objid_query.non_repeaters = 0; + objid_query.valueretrieval = SNMP_G(valueretrieval); +@@ -1550,7 +1550,7 @@ static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version) + } + + php_snmp_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, st, session, &objid_query); +- ++ + efree(objid_query.vars); + + if (session_less_mode) { +@@ -1563,7 +1563,7 @@ static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version) + } + /* }}} */ + +-/* {{{ proto mixed snmpget(string host, string community, mixed object_id [, int timeout [, int retries]]) ++/* {{{ proto mixed snmpget(string host, string community, mixed object_id [, int timeout [, int retries]]) + Fetch a SNMP object */ + PHP_FUNCTION(snmpget) + { +@@ -1571,7 +1571,7 @@ PHP_FUNCTION(snmpget) + } + /* }}} */ + +-/* {{{ proto mixed snmpgetnext(string host, string community, mixed object_id [, int timeout [, int retries]]) ++/* {{{ proto mixed snmpgetnext(string host, string community, mixed object_id [, int timeout [, int retries]]) + Fetch a SNMP object */ + PHP_FUNCTION(snmpgetnext) + { +@@ -1579,7 +1579,7 @@ PHP_FUNCTION(snmpgetnext) + } + /* }}} */ + +-/* {{{ proto mixed snmpwalk(string host, string community, mixed object_id [, int timeout [, int retries]]) ++/* {{{ proto mixed snmpwalk(string host, string community, mixed object_id [, int timeout [, int retries]]) + Return all objects under the specified object id */ + PHP_FUNCTION(snmpwalk) + { +@@ -1595,7 +1595,7 @@ PHP_FUNCTION(snmprealwalk) + } + /* }}} */ + +-/* {{{ proto bool snmpset(string host, string community, mixed object_id, mixed type, mixed value [, int timeout [, int retries]]) ++/* {{{ proto bool snmpset(string host, string community, mixed object_id, mixed type, mixed value [, int timeout [, int retries]]) + Set the value of a SNMP object */ + PHP_FUNCTION(snmpset) + { +@@ -1642,7 +1642,7 @@ PHP_FUNCTION(snmp_set_enum_print) + + netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM, (int) a1); + RETURN_TRUE; +-} ++} + /* }}} */ + + /* {{{ proto bool snmp_set_oid_output_format(int oid_format) +@@ -1670,10 +1670,10 @@ PHP_FUNCTION(snmp_set_oid_output_format) + RETURN_FALSE; + break; + } +-} ++} + /* }}} */ + +-/* {{{ proto mixed snmp2_get(string host, string community, mixed object_id [, int timeout [, int retries]]) ++/* {{{ proto mixed snmp2_get(string host, string community, mixed object_id [, int timeout [, int retries]]) + Fetch a SNMP object */ + PHP_FUNCTION(snmp2_get) + { +@@ -1681,7 +1681,7 @@ PHP_FUNCTION(snmp2_get) + } + /* }}} */ + +-/* {{{ proto mixed snmp2_getnext(string host, string community, mixed object_id [, int timeout [, int retries]]) ++/* {{{ proto mixed snmp2_getnext(string host, string community, mixed object_id [, int timeout [, int retries]]) + Fetch a SNMP object */ + PHP_FUNCTION(snmp2_getnext) + { +@@ -1689,7 +1689,7 @@ PHP_FUNCTION(snmp2_getnext) + } + /* }}} */ + +-/* {{{ proto mixed snmp2_walk(string host, string community, mixed object_id [, int timeout [, int retries]]) ++/* {{{ proto mixed snmp2_walk(string host, string community, mixed object_id [, int timeout [, int retries]]) + Return all objects under the specified object id */ + PHP_FUNCTION(snmp2_walk) + { +@@ -1705,7 +1705,7 @@ PHP_FUNCTION(snmp2_real_walk) + } + /* }}} */ + +-/* {{{ proto bool snmp2_set(string host, string community, mixed object_id, mixed type, mixed value [, int timeout [, int retries]]) ++/* {{{ proto bool snmp2_set(string host, string community, mixed object_id, mixed type, mixed value [, int timeout [, int retries]]) + Set the value of a SNMP object */ + PHP_FUNCTION(snmp2_set) + { +@@ -1821,7 +1821,7 @@ PHP_METHOD(snmp, __construct) + + snmp_object = (php_snmp_object *)zend_object_store_get_object(object TSRMLS_CC); + zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC); +- ++ + if (zend_parse_parameters(argc TSRMLS_CC, "lss|ll", &version, &a1, &a1_len, &a2, &a2_len, &timeout, &retries) == FAILURE) { + zend_restore_error_handling(&error_handling TSRMLS_CC); + return; +@@ -1843,7 +1843,7 @@ PHP_METHOD(snmp, __construct) + if (snmp_object->session) { + netsnmp_session_free(&(snmp_object->session)); + } +- ++ + if (netsnmp_session_init(&(snmp_object->session), version, a1, a2, timeout, retries TSRMLS_CC)) { + return; + } +@@ -1857,7 +1857,7 @@ PHP_METHOD(snmp, __construct) + } + /* }}} */ + +-/* {{{ proto bool SNMP::close() ++/* {{{ proto bool SNMP::close() + Close SNMP session */ + PHP_METHOD(snmp, close) + { +@@ -1900,7 +1900,7 @@ PHP_METHOD(snmp, walk) + } + /* }}} */ + +-/* {{{ proto bool SNMP::set(mixed object_id, mixed type, mixed value) ++/* {{{ proto bool SNMP::set(mixed object_id, mixed type, mixed value) + Set the value of a SNMP object */ + PHP_METHOD(snmp, set) + { +@@ -1918,7 +1918,7 @@ PHP_METHOD(snmp, setSecurity) + int argc = ZEND_NUM_ARGS(); + + snmp_object = (php_snmp_object *)zend_object_store_get_object(object TSRMLS_CC); +- ++ + if (zend_parse_parameters(argc TSRMLS_CC, "s|ssssss", &a1, &a1_len, &a2, &a2_len, &a3, &a3_len, + &a4, &a4_len, &a5, &a5_len, &a6, &a6_len, &a7, &a7_len) == FAILURE) { + RETURN_FALSE; +@@ -1932,7 +1932,7 @@ PHP_METHOD(snmp, setSecurity) + } + /* }}} */ + +-/* {{{ proto long SNMP::getErrno() ++/* {{{ proto long SNMP::getErrno() + Get last error code number */ + PHP_METHOD(snmp, getErrno) + { +@@ -1946,7 +1946,7 @@ PHP_METHOD(snmp, getErrno) + } + /* }}} */ + +-/* {{{ proto long SNMP::getError() ++/* {{{ proto long SNMP::getError() + Get last error message */ + PHP_METHOD(snmp, getError) + { +@@ -2095,6 +2095,14 @@ static int php_snmp_has_property(zval *object, zval *member, int has_set_exists, + } + /* }}} */ + ++static HashTable *php_snmp_get_gc(zval *object, zval ***gc_data, int *gc_data_count TSRMLS_DC) /* {{{ */ ++{ ++ *gc_data = NULL; ++ *gc_data_count = 0; ++ return zend_std_get_properties(object TSRMLS_CC); ++} ++/* }}} */ ++ + /* {{{ php_snmp_get_properties(zval *object) + Returns all object properties. Injects SNMP properties into object on first call */ + static HashTable *php_snmp_get_properties(zval *object TSRMLS_DC) +@@ -2137,23 +2145,23 @@ static int php_snmp_read_info(php_snmp_object *snmp_object, zval **retval TSRMLS + if (snmp_object->session == NULL) { + return SUCCESS; + } +- ++ + MAKE_STD_ZVAL(val); + ZVAL_STRINGL(val, snmp_object->session->peername, strlen(snmp_object->session->peername), 1); + add_assoc_zval(*retval, "hostname", val); +- ++ + MAKE_STD_ZVAL(val); + ZVAL_LONG(val, snmp_object->session->remote_port); + add_assoc_zval(*retval, "port", val); +- ++ + MAKE_STD_ZVAL(val); + ZVAL_LONG(val, snmp_object->session->timeout); + add_assoc_zval(*retval, "timeout", val); +- ++ + MAKE_STD_ZVAL(val); + ZVAL_LONG(val, snmp_object->session->retries); + add_assoc_zval(*retval, "retries", val); +- ++ + return SUCCESS; + } + /* }}} */ +@@ -2226,7 +2234,7 @@ static int php_snmp_write_max_oids(php_snmp_object *snmp_object, zval *newval TS + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "max_oids should be positive integer or NULL, got %ld", Z_LVAL_P(newval)); + } +- ++ + if (newval == &ztmp) { + zval_dtor(newval); + } +@@ -2254,7 +2262,7 @@ static int php_snmp_write_valueretrieval(php_snmp_object *snmp_object, zval *new + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown SNMP value retrieval method '%ld'", Z_LVAL_P(newval)); + ret = FAILURE; + } +- ++ + if (newval == &ztmp) { + zval_dtor(newval); + } +@@ -2297,7 +2305,7 @@ static int php_snmp_write_oid_output_format(php_snmp_object *snmp_object, zval * + convert_to_long(&ztmp); + newval = &ztmp; + } +- ++ + switch(Z_LVAL_P(newval)) { + case NETSNMP_OID_OUTPUT_SUFFIX: + case NETSNMP_OID_OUTPUT_MODULE: +@@ -2332,7 +2340,7 @@ static int php_snmp_write_exceptions_enabled(php_snmp_object *snmp_object, zval + newval = &ztmp; + } + +- snmp_object->exceptions_enabled = Z_LVAL_P(newval); ++ snmp_object->exceptions_enabled = Z_LVAL_P(newval); + + if (newval == &ztmp) { + zval_dtor(newval); +@@ -2401,6 +2409,7 @@ PHP_MINIT_FUNCTION(snmp) + php_snmp_object_handlers.write_property = php_snmp_write_property; + php_snmp_object_handlers.has_property = php_snmp_has_property; + php_snmp_object_handlers.get_properties = php_snmp_get_properties; ++ php_snmp_object_handlers.get_gc = php_snmp_get_gc; + + /* Register SNMP Class */ + INIT_CLASS_ENTRY(ce, "SNMP", php_snmp_class_methods); +@@ -2467,7 +2476,7 @@ PHP_MINIT_FUNCTION(snmp) + PHP_MSHUTDOWN_FUNCTION(snmp) + { + snmp_shutdown("snmpapp"); +- ++ + zend_hash_destroy(&php_snmp_properties); + + return SUCCESS; +diff --git a/ext/snmp/tests/bug72479.phpt b/ext/snmp/tests/bug72479.phpt +new file mode 100644 +index 0000000..0308754 +--- /dev/null ++++ b/ext/snmp/tests/bug72479.phpt +@@ -0,0 +1,35 @@ ++--TEST-- ++Bug #72479: Use After Free Vulnerability in SNMP with GC and unserialize() ++--SKIPIF-- ++<?php ++require_once(dirname(__FILE__).'/skipif.inc'); ++?> ++--FILE-- ++<?php ++$arr = [1, [1, 2, 3, 4, 5], 3, 4, 5]; ++$poc = 'a:3:{i:1;N;i:2;O:4:"snmp":1:{s:11:"quick_print";'.serialize($arr).'}i:1;R:7;}'; ++$out = unserialize($poc); ++gc_collect_cycles(); ++$fakezval = ptr2str(1122334455); ++$fakezval .= ptr2str(0); ++$fakezval .= "\x00\x00\x00\x00"; ++$fakezval .= "\x01"; ++$fakezval .= "\x00"; ++$fakezval .= "\x00\x00"; ++for ($i = 0; $i < 5; $i++) { ++ $v[$i] = $fakezval.$i; ++} ++var_dump($out[1]); ++ ++function ptr2str($ptr) ++{ ++ $out = ''; ++ for ($i = 0; $i < 8; $i++) { ++ $out .= chr($ptr & 0xff); ++ $ptr >>= 8; ++ } ++ return $out; ++} ++?> ++--EXPECT-- ++int(1) +\ No newline at end of file +-- +2.1.4 + diff --git a/bug72513.patch b/bug72513.patch new file mode 100644 index 0000000..5580e46 --- /dev/null +++ b/bug72513.patch @@ -0,0 +1,48 @@ +From 0218acb7e756a469099c4ccfb22bce6c2bd1ef87 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Tue, 12 Jul 2016 21:48:00 -0700 +Subject: [PATCH] Fix for bug #72513 + +--- + TSRM/tsrm_virtual_cwd.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/TSRM/tsrm_virtual_cwd.c b/TSRM/tsrm_virtual_cwd.c +index ba92711..6c22ee8 100644 +--- a/TSRM/tsrm_virtual_cwd.c ++++ b/TSRM/tsrm_virtual_cwd.c +@@ -621,14 +621,14 @@ CWD_API void realpath_cache_del(const char *path, int path_len TSRMLS_DC) /* {{{ + memcmp(path, (*bucket)->path, path_len) == 0) { + realpath_cache_bucket *r = *bucket; + *bucket = (*bucket)->next; +- ++ + /* if the pointers match then only subtract the length of the path */ + if(r->path == r->realpath) { + CWDG(realpath_cache_size) -= sizeof(realpath_cache_bucket) + r->path_len + 1; + } else { + CWDG(realpath_cache_size) -= sizeof(realpath_cache_bucket) + r->path_len + 1 + r->realpath_len + 1; + } +- ++ + free(r); + return; + } else { +@@ -704,7 +704,7 @@ static inline realpath_cache_bucket* realpath_cache_find(const char *path, int p + realpath_cache_bucket *r = *bucket; + *bucket = (*bucket)->next; + +- /* if the pointers match then only subtract the length of the path */ ++ /* if the pointers match then only subtract the length of the path */ + if(r->path == r->realpath) { + CWDG(realpath_cache_size) -= sizeof(realpath_cache_bucket) + r->path_len + 1; + } else { +@@ -1159,7 +1159,7 @@ CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func + int add_slash; + void *tmp; + +- if (path_length == 0 || path_length >= MAXPATHLEN-1) { ++ if (path_length <= 0 || path_length >= MAXPATHLEN-1) { + #ifdef TSRM_WIN32 + # if _MSC_VER < 1300 + errno = EINVAL; diff --git a/bug72519.patch b/bug72519.patch new file mode 100644 index 0000000..a7f67c4 --- /dev/null +++ b/bug72519.patch @@ -0,0 +1,54 @@ +From 7b1572b1772dc92b2e73b7cf6d51dca88a60f411 Mon Sep 17 00:00:00 2001 +From: Pierre Joye <pierre.php@gmail.com> +Date: Tue, 19 Jul 2016 07:11:44 +0700 +Subject: [PATCH] fix #72519, possible OOB using imagegif + +fix #72519, possible OOB using imagegif +--- + ext/gd/libgd/gd_gif_out.c | 18 ++++++++++++++++-- + 1 file changed, 16 insertions(+), 2 deletions(-) + +diff --git a/ext/gd/libgd/gd_gif_out.c b/ext/gd/libgd/gd_gif_out.c +index 1404538..0178dd9 100644 +--- a/ext/gd/libgd/gd_gif_out.c ++++ b/ext/gd/libgd/gd_gif_out.c +@@ -601,14 +601,26 @@ compress(int init_bits, gdIOCtxPtr outfile, gdImagePtr im, GifCtx *ctx) + * code in turn. When the buffer fills up empty it and start over. + */ + +-static unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, ++static const unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, + 0x001F, 0x003F, 0x007F, 0x00FF, + 0x01FF, 0x03FF, 0x07FF, 0x0FFF, + 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + ++ ++/* Arbitrary value to mark output is done. When we see EOFCode, then we don't ++ * expect to see any more data. If we do (e.g. corrupt image inputs), cur_bits ++ * might be negative, so flag it to return early. ++ */ ++#define CUR_BITS_FINISHED -1000 ++ ++ + static void + output(code_int code, GifCtx *ctx) + { ++ if (ctx->cur_bits == CUR_BITS_FINISHED) { ++ return; ++ } ++ + ctx->cur_accum &= masks[ ctx->cur_bits ]; + + if( ctx->cur_bits > 0 ) +@@ -655,8 +667,10 @@ output(code_int code, GifCtx *ctx) + ctx->cur_bits -= 8; + } + +- flush_char(ctx); ++ /* Flag that it's done to prevent re-entry. */ ++ ctx->cur_bits = CUR_BITS_FINISHED; + ++ flush_char(ctx); + } + } + diff --git a/bug72520.patch b/bug72520.patch new file mode 100644 index 0000000..3aadc04 --- /dev/null +++ b/bug72520.patch @@ -0,0 +1,78 @@ +From 81406c0c1d45f75fcc7972ed974d2597abb0b9e9 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Tue, 12 Jul 2016 22:03:40 -0700 +Subject: [PATCH] Fix fir bug #72520 + +--- + ext/zip/zip_stream.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/ext/zip/zip_stream.c b/ext/zip/zip_stream.c +index 400edd6..a9192d2 100644 +--- a/ext/zip/zip_stream.c ++++ b/ext/zip/zip_stream.c +@@ -214,7 +214,7 @@ php_stream *php_stream_zip_open(char *filename, char *path, char *mode STREAMS_D + self = emalloc(sizeof(*self)); + + self->za = stream_za; +- self->zf = zf; ++ self->zf = zf; + self->stream = NULL; + self->cursor = 0; + stream = php_stream_alloc(&php_stream_zipio_ops, self, NULL, mode); +@@ -241,7 +241,7 @@ php_stream *php_stream_zip_opener(php_stream_wrapper *wrapper, + char **opened_path, + php_stream_context *context STREAMS_DC TSRMLS_DC) + { +- int path_len; ++ size_t path_len; + + char *file_basename; + size_t file_basename_len; +@@ -250,7 +250,7 @@ php_stream *php_stream_zip_opener(php_stream_wrapper *wrapper, + struct zip *za; + struct zip_file *zf = NULL; + char *fragment; +- int fragment_len; ++ size_t fragment_len; + int err; + + php_stream *stream = NULL; +@@ -293,7 +293,7 @@ php_stream *php_stream_zip_opener(php_stream_wrapper *wrapper, + self = emalloc(sizeof(*self)); + + self->za = za; +- self->zf = zf; ++ self->zf = zf; + self->stream = NULL; + self->cursor = 0; + stream = php_stream_alloc(&php_stream_zipio_ops, self, NULL, mode); +From 8ebdb1f5fd19cb15dd6ac7700c781ede5dcbba95 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Tue, 19 Jul 2016 22:37:03 -0700 +Subject: [PATCH] Improve fix for #72520 + +--- + ext/zip/zip_stream.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ext/zip/zip_stream.c b/ext/zip/zip_stream.c +index a9192d2..4517122 100644 +--- a/ext/zip/zip_stream.c ++++ b/ext/zip/zip_stream.c +@@ -101,13 +101,13 @@ static int php_zip_ops_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_D + { + struct zip_stat sb; + const char *path = stream->orig_path; +- int path_len = strlen(stream->orig_path); ++ size_t path_len = strlen(stream->orig_path); + char *file_basename; + size_t file_basename_len; + char file_dirname[MAXPATHLEN]; + struct zip *za; + char *fragment; +- int fragment_len; ++ size_t fragment_len; + int err; + + fragment = strchr(path, '#'); diff --git a/bug72533.patch b/bug72533.patch new file mode 100644 index 0000000..63cfa1a --- /dev/null +++ b/bug72533.patch @@ -0,0 +1,80 @@ +Adapted for 5.4, by Remi Collet, from: + + +From aa82e99ed8003c01f1ef4f0940e56b85c5b032d4 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Tue, 12 Jul 2016 22:37:36 -0700 +Subject: [PATCH] Fix bug #72533 (locale_accept_from_http out-of-bounds access) + +--- + ext/intl/locale/locale_methods.c | 18 ++++++++++++++++++ + ext/intl/tests/bug72533.phpt | 30 ++++++++++++++++++++++++++++++ + 2 files changed, 48 insertions(+) + create mode 100644 ext/intl/tests/bug72533.phpt + +diff --git a/ext/intl/locale/locale_methods.c b/ext/intl/locale/locale_methods.c +index 31f60b3..443856f 100644 +--- a/ext/intl/locale/locale_methods.c ++++ b/ext/intl/locale/locale_methods.c +@@ -1596,6 +1596,24 @@ PHP_FUNCTION(locale_accept_from_http) + "locale_accept_from_http: unable to parse input parameters", 0 TSRMLS_CC ); + RETURN_FALSE; + } ++ if(http_accept_len > ULOC_FULLNAME_CAPACITY) { ++ /* check each fragment, if any bigger than capacity, can't do it due to bug #72533 */ ++ char *start = http_accept; ++ char *end; ++ size_t len; ++ do { ++ end = strchr(start, ','); ++ len = end ? end-start : http_accept_len-(start-http_accept); ++ if(len > ULOC_FULLNAME_CAPACITY) { ++ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, ++ "locale_accept_from_http: locale string too long", 0 TSRMLS_CC ); ++ RETURN_FALSE; ++ } ++ if(end) { ++ start = end+1; ++ } ++ } while(end != NULL); ++ } + + available = ures_openAvailableLocales(NULL, &status); + INTL_CHECK_STATUS(status, "locale_accept_from_http: failed to retrieve locale list"); +diff --git a/ext/intl/tests/bug72533.phpt b/ext/intl/tests/bug72533.phpt +new file mode 100644 +index 0000000..c7fcba3 +--- /dev/null ++++ b/ext/intl/tests/bug72533.phpt +@@ -0,0 +1,30 @@ ++--TEST-- ++Bug #72533 (locale_accept_from_http out-of-bounds access) ++--SKIPIF-- ++<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> ++--FILE-- ++<?php ++ ++function ut_main() ++{ ++ $ret = var_export(ut_loc_accept_http(str_repeat('x', 256)), true); ++ $ret .= "\n"; ++ if(intl_is_failure(intl_get_error_code())) { ++ $ret .= var_export(intl_get_error_message(), true); ++ } ++ $ret .= "\n"; ++ $ret .= var_export(ut_loc_accept_http(str_repeat('en,', 256)), true); ++ $ret .= "\n"; ++ if(intl_is_failure(intl_get_error_code())) { ++ $ret .= var_export(intl_get_error_message(), true); ++ } ++ return $ret; ++} ++ ++include_once( 'ut_common.inc' ); ++ut_run(); ++?> ++--EXPECTF-- ++false ++'locale_accept_from_http: locale string too long: U_ILLEGAL_ARGUMENT_ERROR' ++'en' +\ No newline at end of file diff --git a/bug72562.patch b/bug72562.patch new file mode 100644 index 0000000..cbed3d6 --- /dev/null +++ b/bug72562.patch @@ -0,0 +1,73 @@ +From 3798eb6fd5dddb211b01d41495072fd9858d4e32 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Tue, 12 Jul 2016 23:27:45 -0700 +Subject: [PATCH] Fix bug #72562 - destroy var_hash properly + +--- + ext/session/session.c | 3 ++- + ext/session/tests/bug72562.phpt | 44 +++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 46 insertions(+), 1 deletion(-) + create mode 100644 ext/session/tests/bug72562.phpt + +diff --git a/ext/session/session.c b/ext/session/session.c +index f5439ea..cb6cc01 100644 +--- a/ext/session/session.c ++++ b/ext/session/session.c +@@ -837,6 +837,7 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */ + namelen = ((unsigned char)(*p)) & (~PS_BIN_UNDEF); + + if (namelen < 0 || namelen > PS_BIN_MAX || (p + namelen) >= endptr) { ++ PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + return FAILURE; + } + +diff --git a/ext/session/tests/bug72562.phpt b/ext/session/tests/bug72562.phpt +new file mode 100644 +index 0000000..d85e48b +--- /dev/null ++++ b/ext/session/tests/bug72562.phpt +@@ -0,0 +1,44 @@ ++--TEST-- ++Bug #72562: Use After Free in unserialize() with Unexpected Session Deserialization ++--SKIPIF-- ++<?php include('skipif.inc'); ?> ++--FILE-- ++<?php ++ ++ini_set('session.serialize_handler', 'php_binary'); ++session_start(); ++$sess = "\x1xi:1;\x2y"; ++session_decode($sess); ++$uns_1 = '{'; ++$out_1[] = unserialize($uns_1); ++unset($out_1); ++$fakezval = ptr2str(1122334455); ++$fakezval .= ptr2str(0); ++$fakezval .= "\x00\x00\x00\x00"; ++$fakezval .= "\x01"; ++$fakezval .= "\x00"; ++$fakezval .= "\x00\x00"; ++for ($i = 0; $i < 5; $i++) { ++ $v[$i] = $fakezval.$i; ++} ++$uns_2 = 'R:2;'; ++$out_2 = unserialize($uns_2); ++var_dump($out_2); ++ ++function ptr2str($ptr) ++{ ++ $out = ''; ++ for ($i = 0; $i < 8; $i++) { ++ $out .= chr($ptr & 0xff); ++ $ptr >>= 8; ++ } ++ return $out; ++} ++?> ++--EXPECTF-- ++Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/bug72562.php on line %d ++ ++Notice: unserialize(): Error at offset 0 of 1 bytes in %s/bug72562.php on line %d ++ ++Notice: unserialize(): Error at offset 4 of 4 bytes in %s/bug72562.php on line %d ++bool(false) diff --git a/bug72573.patch b/bug72573.patch new file mode 100644 index 0000000..52fa50f --- /dev/null +++ b/bug72573.patch @@ -0,0 +1,464 @@ +Adapted for 5.4, by Remi Collet, from: + + +From 98b9dfaec95e6f910f125ed172cdbd25abd006ec Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Sun, 10 Jul 2016 16:17:54 -0700 +Subject: [PATCH] Fix for HTTP_PROXY issue. + +The following changes are made: +- _SERVER/_ENV only has HTTP_PROXY if the local environment has it, + and only one from the environment. +- getenv('HTTP_PROXY') only returns one from the local environment +- getenv has optional second parameter, telling it to only consider + local environment +--- + UPGRADING | 3 +++ + ext/standard/basic_functions.c | 17 +++++++------ + main/SAPI.c | 48 +++++++++++++++++++----------------- + main/php_variables.c | 56 ++++++++++++++++++++++++++++-------------- + 4 files changed, 76 insertions(+), 48 deletions(-) + +diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c +index 50b6bc7..8cbba14 100644 +--- a/ext/standard/basic_functions.c ++++ b/ext/standard/basic_functions.c +@@ -3955,21 +3955,24 @@ PHP_FUNCTION(long2ip) + * System Functions * + ********************/ + +-/* {{{ proto string getenv(string varname) ++/* {{{ proto string getenv(string varname[, bool local_only]) + Get the value of an environment variable */ + PHP_FUNCTION(getenv) + { + char *ptr, *str; + int str_len; ++ zend_bool local_only = 0; + +- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) { ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &str, &str_len, &local_only) == FAILURE) { + RETURN_FALSE; + } + +- /* SAPI method returns an emalloc()'d string */ +- ptr = sapi_getenv(str, str_len TSRMLS_CC); +- if (ptr) { +- RETURN_STRING(ptr, 0); ++ if (!local_only) { ++ /* SAPI method returns an emalloc()'d string */ ++ ptr = sapi_getenv(str, str_len TSRMLS_CC); ++ if (ptr) { ++ RETURN_STRING(ptr, 0); ++ } + } + #ifdef PHP_WIN32 + { +diff --git a/main/SAPI.c b/main/SAPI.c +index 0dd0b55..8a56c6d 100644 +--- a/main/SAPI.c ++++ b/main/SAPI.c +@@ -1,4 +1,4 @@ +-/* ++/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ +@@ -132,7 +132,7 @@ PHP_FUNCTION(header_register_callback) + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &callback_func) == FAILURE) { + return; + } +- ++ + if (!zend_is_callable(callback_func, 0, &callback_name TSRMLS_CC)) { + efree(callback_name); + RETURN_FALSE; +@@ -160,10 +160,10 @@ static void sapi_run_header_callback(TSRMLS_D) + char *callback_name = NULL; + char *callback_error = NULL; + zval *retval_ptr = NULL; +- ++ + if (zend_fcall_info_init(SG(callback_func), 0, &fci, &SG(fci_cache), &callback_name, &callback_error TSRMLS_CC) == SUCCESS) { + fci.retval_ptr_ptr = &retval_ptr; +- ++ + error = zend_call_function(&fci, &SG(fci_cache) TSRMLS_CC); + if (error == FAILURE) { + goto callback_failed; +@@ -174,13 +174,13 @@ static void sapi_run_header_callback(TSRMLS_D) + callback_failed: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not call the sapi_header_callback"); + } +- ++ + if (callback_name) { + efree(callback_name); + } + if (callback_error) { + efree(callback_error); +- } ++ } + } + + SAPI_API void sapi_handle_post(void *arg TSRMLS_DC) +@@ -386,11 +386,11 @@ SAPI_API void sapi_activate_headers_only(TSRMLS_D) + if (SG(request_info).headers_read == 1) + return; + SG(request_info).headers_read = 1; +- zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct), ++ zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct), + (void (*)(void *)) sapi_free_header, 0); + SG(sapi_headers).send_default_content_type = 1; + +- /* SG(sapi_headers).http_response_code = 200; */ ++ /* SG(sapi_headers).http_response_code = 200; */ + SG(sapi_headers).http_status_line = NULL; + SG(sapi_headers).mimetype = NULL; + SG(read_post_bytes) = 0; +@@ -403,7 +403,7 @@ SAPI_API void sapi_activate_headers_only(TSRMLS_D) + SG(global_request_time) = 0; + + /* +- * It's possible to override this general case in the activate() callback, ++ * It's possible to override this general case in the activate() callback, + * if necessary. + */ + if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) { +@@ -465,8 +465,8 @@ SAPI_API void sapi_activate(TSRMLS_D) + * depending on given content type */ + sapi_read_post_data(TSRMLS_C); + } else { +- /* Any other method with content payload will fill $HTTP_RAW_POST_DATA +- * if it is enabled by always_populate_raw_post_data. ++ /* Any other method with content payload will fill $HTTP_RAW_POST_DATA ++ * if it is enabled by always_populate_raw_post_data. + * It's up to the webserver to decide whether to allow a method or not. */ + SG(request_info).content_type_dup = NULL; + if (sapi_module.default_post_reader) { +@@ -497,14 +497,14 @@ static void sapi_send_headers_free(TSRMLS_D) + SG(sapi_headers).http_status_line = NULL; + } + } +- ++ + SAPI_API void sapi_deactivate(TSRMLS_D) + { + zend_llist_destroy(&SG(sapi_headers).headers); + if (SG(request_info).post_data) { + efree(SG(request_info).post_data); + } else if (SG(server_context)) { +- if(sapi_module.read_post) { ++ if(sapi_module.read_post) { + /* make sure we've consumed all request input data */ + char dummy[SAPI_POST_BLOCK_SIZE]; + int read_bytes; +@@ -516,7 +516,7 @@ SAPI_API void sapi_deactivate(TSRMLS_D) + } + if (SG(request_info).raw_post_data) { + efree(SG(request_info).raw_post_data); +- } ++ } + if (SG(request_info).auth_user) { + efree(SG(request_info).auth_user); + } +@@ -574,7 +574,7 @@ static int sapi_extract_response_code(const char *header_line) + break; + } + } +- ++ + return code; + } + +@@ -594,7 +594,7 @@ static void sapi_update_response_code(int ncode TSRMLS_DC) + SG(sapi_headers).http_response_code = ncode; + } + +-/* ++/* + * since zend_llist_del_element only remove one matched item once, + * we should remove them by ourself + */ +@@ -630,7 +630,7 @@ SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bo + { + sapi_header_line ctr = {0}; + int r; +- ++ + ctr.line = header_line; + ctr.line_len = header_line_len; + +@@ -724,7 +724,7 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC) + } while(header_line_len && isspace(header_line[header_line_len-1])); + header_line[header_line_len]='\0'; + } +- ++ + if (op == SAPI_HEADER_DELETE) { + if (strchr(header_line, ':')) { + efree(header_line); +@@ -762,7 +762,7 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC) + sapi_header.header_len = header_line_len; + + /* Check the header for a few cases that we have special support for in SAPI */ +- if (header_line_len>=5 ++ if (header_line_len>=5 + && !strncasecmp(header_line, "HTTP/", 5)) { + /* filter out the response code */ + sapi_update_response_code(sapi_extract_response_code(header_line) TSRMLS_CC); +@@ -821,8 +821,8 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC) + /* Return a Found Redirect if one is not already specified */ + if (http_response_code) { /* user specified redirect code */ + sapi_update_response_code(http_response_code TSRMLS_CC); +- } else if (SG(request_info).proto_num > 1000 && +- SG(request_info).request_method && ++ } else if (SG(request_info).proto_num > 1000 && ++ SG(request_info).request_method && + strcmp(SG(request_info).request_method, "HEAD") && + strcmp(SG(request_info).request_method, "GET")) { + sapi_update_response_code(303 TSRMLS_CC); +@@ -1011,7 +1011,11 @@ SAPI_API struct stat *sapi_get_stat(TSRMLS_D) + + SAPI_API char *sapi_getenv(char *name, size_t name_len TSRMLS_DC) + { +- if (sapi_module.getenv) { ++ if (!strncasecmp(name, "HTTP_PROXY", name_len)) { ++ /* Ugly fix for HTTP_PROXY issue */ ++ return NULL; ++ } ++ if (sapi_module.getenv) { + char *value, *tmp = sapi_module.getenv(name, name_len TSRMLS_CC); + if (tmp) { + value = estrdup(tmp); +diff --git a/main/php_variables.c b/main/php_variables.c +index bf6b9f3..bbe57d3 100644 +--- a/main/php_variables.c ++++ b/main/php_variables.c +@@ -44,7 +4443,7 @@ PHPAPI void php_register_variable_safe(char *var, char *strval, int str_len, zva + { + zval new_entry; + assert(strval != NULL); +- ++ + /* Prepare value */ + Z_STRLEN(new_entry) = str_len; + Z_STRVAL(new_entry) = estrndup(strval, Z_STRLEN(new_entry)); +@@ -82,7 +82,7 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars + while (*var_name && *var_name==' ') { + var_name++; + } +- ++ + /* + * Prepare variable name + */ +@@ -168,7 +168,7 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars + return; + } + *ip = 0; +- new_idx_len = strlen(index_s); ++ new_idx_len = strlen(index_s); + } + + if (!index) { +@@ -211,7 +211,7 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars + zval_ptr_dtor(&gpc_element); + } + } else { +- /* ++ /* + * According to rfc2965, more specific paths are listed above the less specific ones. + * If we encounter a duplicate cookie name, we should skip it, since it is not possible + * to have the same (plain text) cookie name for the same path and we should not overwrite +@@ -237,7 +237,7 @@ SAPI_API SAPI_POST_HANDLER_FUNC(php_std_post_handler) + + if (SG(request_info).post_data == NULL) { + return; +- } ++ } + + s = SG(request_info).post_data; + e = s + SG(request_info).post_data_length; +@@ -285,7 +285,7 @@ SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data) + int free_buffer = 0; + char *strtok_buf = NULL; + long count = 0; +- ++ + switch (arg) { + case PARSE_POST: + case PARSE_GET: +@@ -358,9 +358,9 @@ SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data) + separator = ";\0"; + break; + } +- ++ + var = php_strtok_r(res, separator, &strtok_buf); +- ++ + while (var) { + val = strchr(var, '='); + +@@ -455,11 +455,11 @@ static void php_build_argv(char *s, zval *track_vars_array TSRMLS_DC) + zval *arr, *argc, *tmp; + int count = 0; + char *ss, *space; +- ++ + if (!(SG(request_info).argc || track_vars_array)) { + return; + } +- ++ + ALLOC_INIT_ZVAL(arr); + array_init(arr); + +@@ -520,7 +520,7 @@ static void php_build_argv(char *s, zval *track_vars_array TSRMLS_DC) + Z_ADDREF_P(argc); + zend_hash_update(&EG(symbol_table), "argv", sizeof("argv"), &arr, sizeof(zval *), NULL); + zend_hash_update(&EG(symbol_table), "argc", sizeof("argc"), &argc, sizeof(zval *), NULL); +- } ++ } + if (track_vars_array) { + Z_ADDREF_P(arr); + Z_ADDREF_P(argc); +@@ -666,7 +666,7 @@ static zend_bool php_auto_globals_create_get(const char *name, uint name_len TSR + + zend_hash_update(&EG(symbol_table), name, name_len + 1, &vars, sizeof(zval *), NULL); + Z_ADDREF_P(vars); +- ++ + return 0; /* don't rearm */ + } + +@@ -693,7 +693,7 @@ static zend_bool php_auto_globals_create_post(const char *name, uint name_len TS + + zend_hash_update(&EG(symbol_table), name, name_len + 1, &vars, sizeof(zval *), NULL); + Z_ADDREF_P(vars); +- ++ + return 0; /* don't rearm */ + } + +@@ -716,7 +716,7 @@ static zend_bool php_auto_globals_create_cookie(const char *name, uint name_len + + zend_hash_update(&EG(symbol_table), name, name_len + 1, &vars, sizeof(zval *), NULL); + Z_ADDREF_P(vars); +- ++ + return 0; /* don't rearm */ + } + +@@ -735,10 +735,26 @@ static zend_bool php_auto_globals_create_files(const char *name, uint name_len T + + zend_hash_update(&EG(symbol_table), name, name_len + 1, &vars, sizeof(zval *), NULL); + Z_ADDREF_P(vars); +- ++ + return 0; /* don't rearm */ + } + ++/* Upgly hack to fix HTTP_PROXY issue */ ++static void check_http_proxy(HashTable *var_table) { ++ if (zend_hash_exists(var_table, "HTTP_PROXY", sizeof("HTTP_PROXY"))) { ++ char *local_proxy = getenv("HTTP_PROXY"); ++ ++ if (!local_proxy) { ++ zend_hash_del(var_table, "HTTP_PROXY", sizeof("HTTP_PROXY")); ++ } else { ++ zval *local_zval; ++ ALLOC_INIT_ZVAL(local_zval); ++ ZVAL_STRING(local_zval, local_proxy, 1); ++ zend_hash_update(var_table, "HTTP_PROXY", sizeof("HTTP_PROXY"), &local_zval, sizeof(zval **), NULL); ++ } ++ } ++} ++ + static zend_bool php_auto_globals_create_server(const char *name, uint name_len TSRMLS_DC) + { + if (PG(variables_order) && (strchr(PG(variables_order),'S') || strchr(PG(variables_order),'s'))) { +@@ -747,7 +763,7 @@ static zend_bool php_auto_globals_create_server(const char *name, uint name_len + if (PG(register_argc_argv)) { + if (SG(request_info).argc) { + zval **argc, **argv; +- ++ + if (zend_hash_find(&EG(symbol_table), "argc", sizeof("argc"), (void**)&argc) == SUCCESS && + zend_hash_find(&EG(symbol_table), "argv", sizeof("argv"), (void**)&argv) == SUCCESS) { + Z_ADDREF_PP(argc); +@@ -759,7 +775,7 @@ static zend_bool php_auto_globals_create_server(const char *name, uint name_len + php_build_argv(SG(request_info).query_string, PG(http_globals)[TRACK_VARS_SERVER] TSRMLS_CC); + } + } +- ++ + } else { + zval *server_vars=NULL; + ALLOC_ZVAL(server_vars); +@@ -771,9 +787,10 @@ static zend_bool php_auto_globals_create_server(const char *name, uint name_len + PG(http_globals)[TRACK_VARS_SERVER] = server_vars; + } + ++ check_http_proxy(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER])); + zend_hash_update(&EG(symbol_table), name, name_len + 1, &PG(http_globals)[TRACK_VARS_SERVER], sizeof(zval *), NULL); + Z_ADDREF_P(PG(http_globals)[TRACK_VARS_SERVER]); +- ++ + return 0; /* don't rearm */ + } + +@@ -787,11 +804,12 @@ static zend_bool php_auto_globals_create_env(const char *name, uint name_len TSR + zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_ENV]); + } + PG(http_globals)[TRACK_VARS_ENV] = env_vars; +- ++ + if (PG(variables_order) && (strchr(PG(variables_order),'E') || strchr(PG(variables_order),'e'))) { + php_import_environment_variables(PG(http_globals)[TRACK_VARS_ENV] TSRMLS_CC); + } + ++ check_http_proxy(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_ENV])); + zend_hash_update(&EG(symbol_table), name, name_len + 1, &PG(http_globals)[TRACK_VARS_ENV], sizeof(zval *), NULL); + Z_ADDREF_P(PG(http_globals)[TRACK_VARS_ENV]); + +From aca4f65c7e98b9f07ac625eaf6be8eadbeb55929 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Tue, 12 Jul 2016 21:35:02 -0700 +Subject: [PATCH] CS fix and comments with bug ID + +--- + main/SAPI.c | 2 +- + main/php_variables.c | 5 +++-- + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/main/SAPI.c b/main/SAPI.c +index 8a56c6d..223c510 100644 +--- a/main/SAPI.c ++++ b/main/SAPI.c +@@ -1012,7 +1012,7 @@ SAPI_API struct stat *sapi_get_stat(TSRMLS_D) + SAPI_API char *sapi_getenv(char *name, size_t name_len TSRMLS_DC) + { + if (!strncasecmp(name, "HTTP_PROXY", name_len)) { +- /* Ugly fix for HTTP_PROXY issue */ ++ /* Ugly fix for HTTP_PROXY issue, see bug #72573 */ + return NULL; + } + if (sapi_module.getenv) { +diff --git a/main/php_variables.c b/main/php_variables.c +index bbe57d3..5977a5e 100644 +--- a/main/php_variables.c ++++ b/main/php_variables.c +@@ -739,8 +739,9 @@ static zend_bool php_auto_globals_create_files(const char *name, uint name_len T + return 0; /* don't rearm */ + } + +-/* Upgly hack to fix HTTP_PROXY issue */ +-static void check_http_proxy(HashTable *var_table) { ++/* Upgly hack to fix HTTP_PROXY issue, see bug #72573 */ ++static void check_http_proxy(HashTable *var_table) ++{ + if (zend_hash_exists(var_table, "HTTP_PROXY", sizeof("HTTP_PROXY"))) { + char *local_proxy = getenv("HTTP_PROXY"); + diff --git a/bug72603.patch b/bug72603.patch new file mode 100644 index 0000000..91d7965 --- /dev/null +++ b/bug72603.patch @@ -0,0 +1,76 @@ +Adapted for 5.4, by Remi Collet, binary patch removed, from: + + +From eebcbd5de38a0f1c2876035402cb770e37476519 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Sun, 17 Jul 2016 16:34:21 -0700 +Subject: [PATCH] Fix bug #72603: Out of bound read in + exif_process_IFD_in_MAKERNOTE + +--- + ext/exif/exif.c | 22 ++++++++++++++++++++-- + ext/exif/tests/bug72603.jpeg | Bin 0 -> 3711 bytes + ext/exif/tests/bug72603.phpt | 11 +++++++++++ + 3 files changed, 31 insertions(+), 2 deletions(-) + create mode 100644 ext/exif/tests/bug72603.jpeg + create mode 100644 ext/exif/tests/bug72603.phpt + +diff --git a/ext/exif/exif.c b/ext/exif/exif.c +index f366acc..760e746 100644 +--- a/ext/exif/exif.c ++++ b/ext/exif/exif.c +@@ -2742,6 +2742,12 @@ static int exif_process_IFD_in_MAKERNOTE(image_info_type *ImageInfo, char * valu + break; + } + ++ if (maker_note->offset >= value_len) { ++ /* Do not go past the value end */ ++ exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "IFD data too short: 0x%04X offset 0x%04X", value_len, maker_note->offset); ++ return FALSE; ++ } ++ + dir_start = value_ptr + maker_note->offset; + + #ifdef EXIF_DEBUG +@@ -2770,10 +2776,19 @@ static int exif_process_IFD_in_MAKERNOTE(image_info_type *ImageInfo, char * valu + offset_base = value_ptr; + break; + case MN_OFFSET_GUESS: ++ if (maker_note->offset + 10 + 4 >= value_len) { ++ /* Can not read dir_start+10 since it's beyond value end */ ++ exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "IFD data too short: 0x%04X", value_len); ++ return FALSE; ++ } + offset_diff = 2 + NumDirEntries*12 + 4 - php_ifd_get32u(dir_start+10, ImageInfo->motorola_intel); + #ifdef EXIF_DEBUG + exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Using automatic offset correction: 0x%04X", ((int)dir_start-(int)offset_base+maker_note->offset+displacement) + offset_diff); + #endif ++ if (offset_diff < 0 || offset_diff >= value_len ) { ++ exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "IFD data bad offset: 0x%04X length 0x%04X", offset_diff, value_len); ++ return FALSE; ++ } + offset_base = value_ptr + offset_diff; + break; + default: +@@ -2782,7 +2797,7 @@ static int exif_process_IFD_in_MAKERNOTE(image_info_type *ImageInfo, char * valu + } + + if ((2+NumDirEntries*12) > value_len) { +- exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Illegal IFD size: 2 + x%04X*12 = x%04X > x%04X", NumDirEntries, 2+NumDirEntries*12, value_len); ++ exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Illegal IFD size: 2 + 0x%04X*12 = 0x%04X > 0x%04X", NumDirEntries, 2+NumDirEntries*12, value_len); + return FALSE; + } + +@@ -3068,7 +3083,10 @@ static int exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, cha + break; + + case TAG_MAKER_NOTE: +- exif_process_IFD_in_MAKERNOTE(ImageInfo, value_ptr, byte_count, offset_base, IFDlength, displacement TSRMLS_CC); ++ if (!exif_process_IFD_in_MAKERNOTE(ImageInfo, value_ptr, byte_count, offset_base, IFDlength, displacement TSRMLS_CC)) { ++ EFREE_IF(outside); ++ return FALSE; ++ } + break; + + case TAG_EXIF_IFD_POINTER: + diff --git a/bug72606.patch b/bug72606.patch new file mode 100644 index 0000000..1d2707a --- /dev/null +++ b/bug72606.patch @@ -0,0 +1,152 @@ +From e6c48213c22ed50b2b987b479fcc1ac709394caa Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Mon, 18 Jul 2016 21:44:39 -0700 +Subject: [PATCH] Fix bug #72606: heap-buffer-overflow (write) + simplestring_addn simplestring.c + +--- + ext/xmlrpc/libxmlrpc/simplestring.c | 61 ++++++++++++++++++++++--------------- + ext/xmlrpc/libxmlrpc/simplestring.h | 2 +- + 2 files changed, 38 insertions(+), 25 deletions(-) + +diff --git a/ext/xmlrpc/libxmlrpc/simplestring.c b/ext/xmlrpc/libxmlrpc/simplestring.c +index a084d0e..6477734 100644 +--- a/ext/xmlrpc/libxmlrpc/simplestring.c ++++ b/ext/xmlrpc/libxmlrpc/simplestring.c +@@ -5,28 +5,28 @@ + Epinions.com may be contacted at feedback@epinions-inc.com + */ + +-/* +- Copyright 2000 Epinions, Inc. ++/* ++ Copyright 2000 Epinions, Inc. + +- Subject to the following 3 conditions, Epinions, Inc. permits you, free +- of charge, to (a) use, copy, distribute, modify, perform and display this +- software and associated documentation files (the "Software"), and (b) +- permit others to whom the Software is furnished to do so as well. ++ Subject to the following 3 conditions, Epinions, Inc. permits you, free ++ of charge, to (a) use, copy, distribute, modify, perform and display this ++ software and associated documentation files (the "Software"), and (b) ++ permit others to whom the Software is furnished to do so as well. + +- 1) The above copyright notice and this permission notice shall be included +- without modification in all copies or substantial portions of the +- Software. ++ 1) The above copyright notice and this permission notice shall be included ++ without modification in all copies or substantial portions of the ++ Software. + +- 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF +- ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY +- IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR +- PURPOSE OR NONINFRINGEMENT. ++ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF ++ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY ++ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR ++ PURPOSE OR NONINFRINGEMENT. + +- 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, +- SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT +- OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING +- NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH +- DAMAGES. ++ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, ++ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT ++ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING ++ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH ++ DAMAGES. + + */ + +@@ -71,7 +71,7 @@ static const char rcsid[] = "#(@) $Id$"; + * + * Oh, and it is also binary safe, ie it can handle strings with embedded NULLs, + * so long as the real length is passed in. +- * ++ * + * And the masses rejoiced. + * + * BUGS +@@ -136,7 +136,7 @@ static void simplestring_init_str(simplestring* string) { + * NOTES + * This function is very fast as it does not de-allocate any memory. + * SEE ALSO +- * ++ * + * SOURCE + */ + void simplestring_clear(simplestring* string) { +@@ -190,18 +190,31 @@ void simplestring_free(simplestring* string) { + * simplestring_add () + * SOURCE + */ +-void simplestring_addn(simplestring* target, const char* source, int add_len) { ++void simplestring_addn(simplestring* target, const char* source, size_t add_len) { ++ size_t newsize = target->size, incr = 0; + if(target && source) { + if(!target->str) { + simplestring_init_str(target); + } ++ ++ if((SIZE_MAX - add_len) < target->len || (SIZE_MAX - add_len - 1) < target->len) { ++ /* check for overflows, if there's a potential overflow do nothing */ ++ return; ++ } ++ + if(target->len + add_len + 1 > target->size) { + /* newsize is current length + new length */ +- int newsize = target->len + add_len + 1; +- int incr = target->size * 2; ++ newsize = target->len + add_len + 1; ++ incr = target->size * 2; + + /* align to SIMPLESTRING_INCR increments */ +- newsize = newsize - (newsize % incr) + incr; ++ if (incr) { ++ newsize = newsize - (newsize % incr) + incr; ++ } ++ if(newsize < (target->len + add_len + 1)) { ++ /* some kind of overflow happened */ ++ return; ++ } + target->str = (char*)realloc(target->str, newsize); + + target->size = target->str ? newsize : 0; +diff --git a/ext/xmlrpc/libxmlrpc/simplestring.h b/ext/xmlrpc/libxmlrpc/simplestring.h +index c5d98cf..7e88cd0 100644 +--- a/ext/xmlrpc/libxmlrpc/simplestring.h ++++ b/ext/xmlrpc/libxmlrpc/simplestring.h +@@ -63,7 +63,7 @@ void simplestring_init(simplestring* string); + void simplestring_clear(simplestring* string); + void simplestring_free(simplestring* string); + void simplestring_add(simplestring* string, const char* add); +-void simplestring_addn(simplestring* string, const char* add, int add_len); ++void simplestring_addn(simplestring* string, const char* add, size_t add_len); + + #ifdef __cplusplus + } +From 33c1a55b40900c61ce7e162648eb71ce9b25837c Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Tue, 19 Jul 2016 00:13:25 -0700 +Subject: [PATCH] Apparently some envs miss SIZE_MAX + +--- + ext/xmlrpc/libxmlrpc/simplestring.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/ext/xmlrpc/libxmlrpc/simplestring.c b/ext/xmlrpc/libxmlrpc/simplestring.c +index 6477734..c88754f 100644 +--- a/ext/xmlrpc/libxmlrpc/simplestring.c ++++ b/ext/xmlrpc/libxmlrpc/simplestring.c +@@ -172,6 +172,9 @@ void simplestring_free(simplestring* string) { + } + /******/ + ++#ifndef SIZE_MAX ++#define SIZE_MAX ((size_t)-1) ++#endif + /****f* FUNC/simplestring_addn + * NAME + * simplestring_addn diff --git a/bug72613.patch b/bug72613.patch new file mode 100644 index 0000000..231f573 --- /dev/null +++ b/bug72613.patch @@ -0,0 +1,281 @@ +Adapted for 5.4, by Remi Collet, binary patch removed, from: + + +From f3feddb5b45b5abd93abb1a95044b7e099d51c84 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Mon, 18 Jul 2016 22:20:45 -0700 +Subject: [PATCH] Partial fix for bug #72613 - do not treat negative returns + from bz2 as size_t + +--- + ext/bz2/bz2.c | 80 +++++++++++++++++++++++--------------------- + ext/bz2/tests/72613.bz2 | Bin 0 -> 351 bytes + ext/bz2/tests/bug72613.phpt | 23 +++++++++++++ + 3 files changed, 65 insertions(+), 38 deletions(-) + create mode 100644 ext/bz2/tests/72613.bz2 + create mode 100644 ext/bz2/tests/bug72613.phpt + +diff --git a/ext/bz2/bz2.c b/ext/bz2/bz2.c +index de3250e..7cfcaa8 100644 +--- a/ext/bz2/bz2.c ++++ b/ext/bz2/bz2.c +@@ -15,7 +15,7 @@ + | Author: Sterling Hughes <sterling@php.net> | + +----------------------------------------------------------------------+ + */ +- ++ + /* $Id$ */ + + #ifdef HAVE_CONFIG_H +@@ -137,29 +137,33 @@ struct php_bz2_stream_data_t { + static size_t php_bz2iop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) + { + struct php_bz2_stream_data_t *self = (struct php_bz2_stream_data_t *) stream->abstract; +- size_t ret; +- +- ret = BZ2_bzread(self->bz_file, buf, count); ++ int bz2_ret; ++ ++ bz2_ret = BZ2_bzread(self->bz_file, buf, count); + +- if (ret == 0) { ++ if (bz2_ret < 0) { ++ stream->eof = 1; ++ return -1; ++ } ++ if (bz2_ret == 0) { + stream->eof = 1; + } + +- return ret; ++ return (size_t)bz2_ret; + } + + static size_t php_bz2iop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) + { + struct php_bz2_stream_data_t *self = (struct php_bz2_stream_data_t *) stream->abstract; + +- return BZ2_bzwrite(self->bz_file, (char*)buf, count); ++ return BZ2_bzwrite(self->bz_file, (char*)buf, count); + } + + static int php_bz2iop_close(php_stream *stream, int close_handle TSRMLS_DC) + { + struct php_bz2_stream_data_t *self = (struct php_bz2_stream_data_t *)stream->abstract; + int ret = EOF; +- ++ + if (close_handle) { + BZ2_bzclose(self->bz_file); + } +@@ -191,11 +195,11 @@ php_stream_ops php_stream_bz2io_ops = { + }; + + /* {{{ Bzip2 stream openers */ +-PHP_BZ2_API php_stream *_php_stream_bz2open_from_BZFILE(BZFILE *bz, ++PHP_BZ2_API php_stream *_php_stream_bz2open_from_BZFILE(BZFILE *bz, + char *mode, php_stream *innerstream STREAMS_DC TSRMLS_DC) + { + struct php_bz2_stream_data_t *self; +- ++ + self = emalloc(sizeof(*self)); + + self->stream = innerstream; +@@ -226,7 +230,7 @@ PHP_BZ2_API php_stream *_php_stream_bz2open(php_stream_wrapper *wrapper, + virtual_filepath_ex(path, &path_copy, NULL TSRMLS_CC); + #else + path_copy = path; +-#endif ++#endif + + if (php_check_open_basedir(path_copy TSRMLS_CC)) { + #ifdef VIRTUAL_DIR +@@ -234,7 +238,7 @@ PHP_BZ2_API php_stream *_php_stream_bz2open(php_stream_wrapper *wrapper, + #endif + return NULL; + } +- ++ + /* try and open it directly first */ + bz_file = BZ2_bzopen(path_copy, mode); + +@@ -245,11 +249,11 @@ PHP_BZ2_API php_stream *_php_stream_bz2open(php_stream_wrapper *wrapper, + free(path_copy); + #endif + path_copy = NULL; +- ++ + if (bz_file == NULL) { + /* that didn't work, so try and get something from the network/wrapper */ + stream = php_stream_open_wrapper(path, mode, options | STREAM_WILL_CAST, opened_path); +- ++ + if (stream) { + int fd; + if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD, (void **) &fd, REPORT_ERRORS)) { +@@ -264,7 +268,7 @@ PHP_BZ2_API php_stream *_php_stream_bz2open(php_stream_wrapper *wrapper, + VCWD_UNLINK(*opened_path); + } + } +- ++ + if (bz_file) { + retstream = _php_stream_bz2open_from_BZFILE(bz_file, mode, stream STREAMS_REL_CC TSRMLS_CC); + if (retstream) { +@@ -340,7 +344,7 @@ static PHP_FUNCTION(bzread) + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &bz, &len)) { + RETURN_FALSE; + } +- ++ + php_stream_from_zval(stream, &bz); + + if ((len + 1) < 1) { +@@ -350,13 +354,13 @@ static PHP_FUNCTION(bzread) + + Z_STRVAL_P(return_value) = emalloc(len + 1); + Z_STRLEN_P(return_value) = php_stream_read(stream, Z_STRVAL_P(return_value), len); +- ++ + if (Z_STRLEN_P(return_value) < 0) { + efree(Z_STRVAL_P(return_value)); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not read valid bz2 data from stream"); +- RETURN_FALSE; ++ RETURN_FALSE; + } +- ++ + Z_STRVAL_P(return_value)[Z_STRLEN_P(return_value)] = 0; + Z_TYPE_P(return_value) = IS_STRING; + } +@@ -372,7 +376,7 @@ static PHP_FUNCTION(bzopen) + + BZFILE *bz; /* The compressed file stream */ + php_stream *stream = NULL; +- ++ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zs", &file, &mode, &mode_len) == FAILURE) { + return; + } +@@ -388,15 +392,15 @@ static PHP_FUNCTION(bzopen) + php_error_docref(NULL TSRMLS_CC, E_WARNING, "filename cannot be empty"); + RETURN_FALSE; + } +- ++ + if (CHECK_ZVAL_NULL_PATH(*file)) { + RETURN_FALSE; + } + + stream = php_stream_bz2open(NULL, +- Z_STRVAL_PP(file), +- mode, +- REPORT_ERRORS, ++ Z_STRVAL_PP(file), ++ mode, ++ REPORT_ERRORS, + NULL); + } else if (Z_TYPE_PP(file) == IS_RESOURCE) { + /* If it is a resource, than its a stream resource */ +@@ -405,7 +409,7 @@ static PHP_FUNCTION(bzopen) + + php_stream_from_zval(stream, file); + stream_mode_len = strlen(stream->mode); +- ++ + if (stream_mode_len != 1 && !(stream_mode_len == 2 && memchr(stream->mode, 'b', 2))) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot use stream opened in mode '%s'", stream->mode); + RETURN_FALSE; +@@ -439,7 +443,7 @@ static PHP_FUNCTION(bzopen) + if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_FD, (void *) &fd, REPORT_ERRORS)) { + RETURN_FALSE; + } +- ++ + bz = BZ2_bzdopen(fd, mode); + + stream = php_stream_bz2open_from_BZFILE(bz, mode, stream); +@@ -493,7 +497,7 @@ static PHP_FUNCTION(bzcompress) + work_factor = 0, /* Work factor for compression algorithm */ + argc; /* Argument count */ + int source_len; /* Length of the source data */ +- unsigned int dest_len; /* Length of the destination buffer */ ++ unsigned int dest_len; /* Length of the destination buffer */ + + argc = ZEND_NUM_ARGS(); + +@@ -502,19 +506,19 @@ static PHP_FUNCTION(bzcompress) + } + + /* Assign them to easy to use variables, dest_len is initially the length of the data +- + .01 x length of data + 600 which is the largest size the results of the compression +- could possibly be, at least that's what the libbz2 docs say (thanks to jeremy@nirvani.net ++ + .01 x length of data + 600 which is the largest size the results of the compression ++ could possibly be, at least that's what the libbz2 docs say (thanks to jeremy@nirvani.net + for pointing this out). */ + dest_len = (unsigned int) (source_len + (0.01 * source_len) + 600); +- ++ + /* Allocate the destination buffer */ + dest = emalloc(dest_len + 1); +- ++ + /* Handle the optional arguments */ + if (argc > 1) { + block_size = zblock_size; + } +- ++ + if (argc > 2) { + work_factor = zwork_factor; + } +@@ -564,7 +568,7 @@ static PHP_FUNCTION(bzdecompress) + /* in most cases bz2 offers at least 2:1 compression, so we use that as our base */ + bzs.avail_out = source_len * 2; + bzs.next_out = dest = emalloc(bzs.avail_out + 1); +- ++ + while ((error = BZ2_bzDecompress(&bzs)) == BZ_OK && bzs.avail_in > 0) { + /* compression is better then 2:1, need to allocate more memory */ + bzs.avail_out = source_len; +@@ -590,13 +594,13 @@ static PHP_FUNCTION(bzdecompress) + /* {{{ php_bz2_error() + The central error handling interface, does the work for bzerrno, bzerrstr and bzerror */ + static void php_bz2_error(INTERNAL_FUNCTION_PARAMETERS, int opt) +-{ ++{ + zval *bzp; /* BZip2 Resource Pointer */ + php_stream *stream; + const char *errstr; /* Error string */ + int errnum; /* Error number */ + struct php_bz2_stream_data_t *self; +- ++ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &bzp) == FAILURE) { + return; + } +@@ -608,10 +612,10 @@ static void php_bz2_error(INTERNAL_FUNCTION_PARAMETERS, int opt) + } + + self = (struct php_bz2_stream_data_t *) stream->abstract; +- ++ + /* Fetch the error information */ + errstr = BZ2_bzerror(self->bz_file, &errnum); +- ++ + /* Determine what to return */ + switch (opt) { + case PHP_BZ_ERRNO: +@@ -622,7 +626,7 @@ static void php_bz2_error(INTERNAL_FUNCTION_PARAMETERS, int opt) + break; + case PHP_BZ_ERRBOTH: + array_init(return_value); +- ++ + add_assoc_long (return_value, "errno", errnum); + add_assoc_string(return_value, "errstr", (char*)errstr, 1); + break; + diff --git a/bug72618.patch b/bug72618.patch new file mode 100644 index 0000000..04814ab --- /dev/null +++ b/bug72618.patch @@ -0,0 +1,110 @@ +Adapted for 5.4, by Remi Collet, binary patch removed, from: + + +From 41131cd41d2fd2e0c2f332a27988df75659c42e4 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Mon, 18 Jul 2016 23:21:51 -0700 +Subject: [PATCH] Fix bug #72618: NULL Pointer Dereference in + exif_process_user_comment + +--- + ext/exif/exif.c | 17 +++++++++++------ + ext/exif/tests/bug72618.jpg | Bin 0 -> 3711 bytes + ext/exif/tests/bug72618.phpt | 11 +++++++++++ + 3 files changed, 22 insertions(+), 6 deletions(-) + create mode 100644 ext/exif/tests/bug72618.jpg + create mode 100644 ext/exif/tests/bug72618.phpt + +diff --git a/ext/exif/exif.c b/ext/exif/exif.c +index 760e746..74b652b 100644 +--- a/ext/exif/exif.c ++++ b/ext/exif/exif.c +@@ -2623,6 +2623,7 @@ static int exif_process_user_comment(image_info_type *ImageInfo, char **pszInfoP + *pszEncoding = NULL; + /* Copy the comment */ + if (ByteCount>=8) { ++ const zend_encoding *from, *to; + if (!memcmp(szValuePtr, "UNICODE\0", 8)) { + *pszEncoding = estrdup((const char*)szValuePtr); + szValuePtr = szValuePtr+8; +@@ -2643,14 +2644,16 @@ static int exif_process_user_comment(image_info_type *ImageInfo, char **pszInfoP + } else { + decode = ImageInfo->decode_unicode_le; + } ++ to = zend_multibyte_fetch_encoding(ImageInfo->encode_unicode TSRMLS_CC); ++ from = zend_multibyte_fetch_encoding(decode TSRMLS_CC); + /* XXX this will fail again if encoding_converter returns on error something different than SIZE_MAX */ +- if (zend_multibyte_encoding_converter( ++ if (!to || !from || zend_multibyte_encoding_converter( + (unsigned char**)pszInfoPtr, + &len, + (unsigned char*)szValuePtr, + ByteCount, +- zend_multibyte_fetch_encoding(ImageInfo->encode_unicode TSRMLS_CC), +- zend_multibyte_fetch_encoding(decode TSRMLS_CC) ++ to, ++ from + TSRMLS_CC) == (size_t)-1) { + len = exif_process_string_raw(pszInfoPtr, szValuePtr, ByteCount); + } +@@ -2665,13 +2668,15 @@ static int exif_process_user_comment(image_info_type *ImageInfo, char **pszInfoP + szValuePtr = szValuePtr+8; + ByteCount -= 8; + /* XXX this will fail again if encoding_converter returns on error something different than SIZE_MAX */ +- if (zend_multibyte_encoding_converter( ++ to = zend_multibyte_fetch_encoding(ImageInfo->encode_jis TSRMLS_CC); ++ from = zend_multibyte_fetch_encoding(ImageInfo->motorola_intel ? ImageInfo->decode_jis_be : ImageInfo->decode_jis_le TSRMLS_CC); ++ if (!to || !from || zend_multibyte_encoding_converter( + (unsigned char**)pszInfoPtr, + &len, + (unsigned char*)szValuePtr, + ByteCount, +- zend_multibyte_fetch_encoding(ImageInfo->encode_jis TSRMLS_CC), +- zend_multibyte_fetch_encoding(ImageInfo->motorola_intel ? ImageInfo->decode_jis_be : ImageInfo->decode_jis_le TSRMLS_CC) ++ to, ++ from + TSRMLS_CC) == (size_t)-1) { + len = exif_process_string_raw(pszInfoPtr, szValuePtr, ByteCount); + } + +From 1364742be9757e594fd1b203d45805106ecd31c7 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Mon, 18 Jul 2016 23:30:51 -0700 +Subject: [PATCH] Fix tests + +--- + ext/exif/tests/bug54002.phpt | 6 +----- + ext/exif/tests/bug62523_2.phpt | 6 ++++-- + 2 files changed, 5 insertions(+), 7 deletions(-) + +diff --git a/ext/exif/tests/bug54002.phpt b/ext/exif/tests/bug54002.phpt +index c51fa58..8f85339 100644 +--- a/ext/exif/tests/bug54002.phpt ++++ b/ext/exif/tests/bug54002.phpt +@@ -13,8 +13,4 @@ exif_read_data(__DIR__ . '/bug54002_2.jpeg'); + --EXPECTF-- + Warning: exif_read_data(bug54002_1.jpeg): Process tag(x0205=UndefinedTa): Illegal byte_count in %sbug54002.php on line %d + +-Warning: exif_read_data(bug54002_1.jpeg): Process tag(xA000=FlashPixVer): Illegal pointer offset(%s) in %sbug54002.php on line %d +- +-Warning: exif_read_data(bug54002_2.jpeg): Process tag(x0205=UndefinedTa): Illegal byte_count in %sbug54002.php on line %d +- +-Warning: exif_read_data(bug54002_2.jpeg): Process tag(xA000=FlashPixVer): Illegal pointer offset(%s) in %sbug54002.php on line %d ++Warning: exif_read_data(bug54002_2.jpeg): Process tag(x0205=UndefinedTa): Illegal byte_count in %sbug54002.php on line %d +\ No newline at end of file +diff --git a/ext/exif/tests/bug62523_2.phpt b/ext/exif/tests/bug62523_2.phpt +index ddc8ae8..c533d42 100644 +--- a/ext/exif/tests/bug62523_2.phpt ++++ b/ext/exif/tests/bug62523_2.phpt +@@ -10,7 +10,9 @@ echo "Test\n"; + var_dump(count(exif_read_data(__DIR__."/bug62523_2.jpg"))); + ?> + Done +---EXPECT-- ++--EXPECTF-- + Test +-int(76) ++ ++Warning: exif_read_data(bug62523_2.jpg): IFD data bad offset: 0xADB23672 length 0x0D94 in %s/bug62523_2.php on line %d ++int(30) + Done @@ -1,13 +1,16 @@ -===== 5.5.45-10 (2016-06-23) +===== 5.5.45-11 (2016-07-22) $ grep -r 'Tests failed' /var/lib/mock/*/build.log -/var/lib/mock/el5i/build.log:Tests failed : 7 +/var/lib/mock/el5i/build.log:Tests failed : 9 /var/lib/mock/el5x/build.log:Tests failed : 3 /var/lib/mock/el6i/build.log:Tests failed : 5 /var/lib/mock/el6x/build.log:Tests failed : 1 /var/lib/mock/el7x/build.log:Tests failed : 0 +el5i + IPv4 Loopback test [ext/sockets/tests/ipv4loop.phpt] + ext/sockets - socket_getpeername_ipv4loop - basic test [ext/sockets/tests/socket_getpeername_ipv4loop.phpt] el5i, el5x Bug #33414 [1] (Comprehensive list of incorrect days returned after strotime() / date() tests) [ext/date/tests/bug33414-1.phpt] Bug #66501: EC private key support in openssl_sign [ext/openssl/tests/bug66501.phpt] @@ -98,7 +98,7 @@ Summary: PHP scripting language for creating dynamic web sites Name: php Version: 5.4.45 -Release: 10%{?dist} +Release: 11%{?dist} # All files licensed under PHP version 3.01, except # Zend is licensed under Zend # TSRM is licensed under BSD @@ -200,6 +200,19 @@ Patch239: bug72433.patch Patch240: bug72434.patch Patch241: bug72455.patch Patch242: bug72446.patch +Patch243: bug70480.patch +Patch244: bug69975.patch +Patch245: bug72479.patch +Patch246: bug72573.patch +Patch247: bug72513.patch +Patch248: bug72520.patch +Patch249: bug72533.patch +Patch250: bug72562.patch +Patch251: bug72603.patch +Patch252: bug72606.patch +Patch253: bug72613.patch +Patch254: bug72618.patch +Patch255: bug72519.patch # Fixes for tests # no_NO issue @@ -950,6 +963,19 @@ rm -f ext/json/utf8_to_utf16.* %patch240 -p1 -b .bug72434 %patch241 -p1 -b .bug72455 %patch242 -p1 -b .bug72446 +%patch243 -p1 -b .bug70480 +%patch244 -p1 -b .bug69975 +%patch245 -p1 -b .bug72479 +%patch246 -p1 -b .bug72573 +%patch247 -p1 -b .bug72513 +%patch248 -p1 -b .bug72520 +%patch249 -p1 -b .bug72533 +%patch250 -p1 -b .bug72562 +%patch251 -p1 -b .bug72603 +%patch252 -p1 -b .bug72606 +%patch253 -p1 -b .bug72613 +%patch254 -p1 -b .bug72618 +%patch255 -p1 -b .bug72519 # Fixes for tests %patch301 -p1 -b .datetests2 @@ -1839,6 +1865,23 @@ fi %changelog +* Fri Jul 22 2016 Remi Collet <remi@fedoraproject.org> 5.4.45-11 +- Fix #70480: php_url_parse_ex() buffer overflow read +- Fix #69975: PHP segfaults when accessing nvarchar(max) defined columns +- Fix #72479: Use After Free Vulnerability in SNMP with GC and unserialize() +- Fix #72573: HTTP_PROXY is improperly trusted by some PHP libraries + CVE-2016-5385 +- Fix #72513: buffer overflow vulnerability in virtual_file_ex +- Fix #72520: buffer overflow vulnerability in php_stream_zip_opener +- Fix #72533: locale_accept_from_http out-of-bounds access +- Fix #72562: Use After Free in unserialize() with Unexpected Session + Deserialization +- Fix #72603: Out of bound read in exif_process_IFD_in_MAKERNOTE +- Fix #72606: heap-buffer-overflow (write) simplestring_addn simplestring.c +- Partial fix #72613: do not treat negative returns from bz2 as size_t +- Fix #72618: NULL Pointer Dereference in exif_process_user_comment +- Fix #72519: possible OOB using imagegif + * Tue Jun 21 2016 Remi Collet <remi@fedoraproject.org> 5.4.45-10 - Fix #66387: Stack overflow with imagefilltoborder - Fix #72340: Double Free Courruption in wddx_deserialize |