From d9b67ab38a64fbfc9f4e78c2ac10778a973e6e47 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Sun, 29 May 2016 09:34:18 +0200 Subject: PHP 5.4.45 + security fix from 5.5.36 --- bug71331.patch | 54 ++++++++++++ bug72114.patch | 75 ++++++++++++++++ bug72135.patch | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ bug72241.patch | 46 ++++++++++ bugoverflow.patch | 37 ++++++++ failed.txt | 7 +- php.spec | 23 ++++- 7 files changed, 496 insertions(+), 3 deletions(-) create mode 100644 bug71331.patch create mode 100644 bug72114.patch create mode 100644 bug72135.patch create mode 100644 bug72241.patch create mode 100644 bugoverflow.patch diff --git a/bug71331.patch b/bug71331.patch new file mode 100644 index 0000000..0151693 --- /dev/null +++ b/bug71331.patch @@ -0,0 +1,54 @@ +Backported from 5.5 for 5.4 by Remi Collet +binary patch dropped + + +From 9649ca1630433473a307d015ba1a79a4a7a779f5 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev +Date: Thu, 14 Jan 2016 22:58:40 -0800 +Subject: [PATCH] Fixed bug #71331 - Uninitialized pointer in + phar_make_dirstream() + +--- + ext/phar/dirstream.c | 3 ++- + ext/phar/tar.c | 2 +- + ext/phar/tests/bug71331.phpt | 15 +++++++++++++++ + ext/phar/tests/bug71331.tar | Bin 0 -> 2560 bytes + 4 files changed, 18 insertions(+), 2 deletions(-) + create mode 100644 ext/phar/tests/bug71331.phpt + create mode 100644 ext/phar/tests/bug71331.tar + +diff --git a/ext/phar/dirstream.c b/ext/phar/dirstream.c +index 75cf049..94958a2 100644 +--- a/ext/phar/dirstream.c ++++ b/ext/phar/dirstream.c +@@ -207,6 +207,7 @@ static php_stream *phar_make_dirstream(c + zend_hash_internal_pointer_reset(manifest); + + while (FAILURE != zend_hash_has_more_elements(manifest)) { ++ keylen = 0; + if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(manifest, &key, &keylen, &unused, 0, NULL)) { + break; + } +@@ -214,7 +215,7 @@ static php_stream *phar_make_dirstream(c + PHAR_STR(key, str_key); + + if (keylen <= (uint)dirlen) { +- if (keylen < (uint)dirlen || !strncmp(str_key, dir, dirlen)) { ++ if (keylen == 0 || keylen < (uint)dirlen || !strncmp(str_key, dir, dirlen)) { + PHAR_STR_FREE(str_key); + if (SUCCESS != zend_hash_move_forward(manifest)) { + break; +diff --git a/ext/phar/tar.c b/ext/phar/tar.c +index 3a4bd49..bf19e08 100644 +--- a/ext/phar/tar.c ++++ b/ext/phar/tar.c +@@ -347,7 +347,7 @@ bail: + entry.filename_len = entry.uncompressed_filesize; + + /* Check for overflow - bug 61065 */ +- if (entry.filename_len == UINT_MAX) { ++ if (entry.filename_len == UINT_MAX || entry.filename_len == 0) { + if (error) { + spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (invalid entry size)", fname); + } + diff --git a/bug72114.patch b/bug72114.patch new file mode 100644 index 0000000..0e9eca7 --- /dev/null +++ b/bug72114.patch @@ -0,0 +1,75 @@ +Backported from 5.5 for 5.4 by Remi Collet + + +From abd159cce48f3e34f08e4751c568e09677d5ec9c Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev +Date: Mon, 9 May 2016 21:55:29 -0700 +Subject: [PATCH] Fix bug #72114 - int/size_t confusion in fread + +--- + ext/standard/file.c | 6 ++++++ + ext/standard/tests/file/bug72114.phpt | 12 ++++++++++++ + 2 files changed, 18 insertions(+) + create mode 100644 ext/standard/tests/file/bug72114.phpt + +diff --git a/ext/standard/file.c b/ext/standard/file.c +index 0abc022..e39c84f 100644 +--- a/ext/standard/file.c ++++ b/ext/standard/file.c +@@ -1755,6 +1755,12 @@ PHPAPI PHP_FUNCTION(fread) + RETURN_FALSE; + } + ++ if (len > INT_MAX) { ++ /* string length is int in 5.x so we can not read more than int */ ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length parameter must be no more than %d", INT_MAX); ++ RETURN_FALSE; ++ } ++ + Z_STRVAL_P(return_value) = emalloc(len + 1); + Z_STRLEN_P(return_value) = php_stream_read(stream, Z_STRVAL_P(return_value), len); + +diff --git a/ext/standard/tests/file/bug72114.phpt b/ext/standard/tests/file/bug72114.phpt +new file mode 100644 +index 0000000..5e591ee +--- /dev/null ++++ b/ext/standard/tests/file/bug72114.phpt +@@ -0,0 +1,12 @@ ++--TEST-- ++Bug #72114 (Integer underflow / arbitrary null write in fread/gzread) ++--FILE-- ++ ++Done ++--EXPECTF-- ++Warning: fread(): Length parameter must be no more than 2147483647 in %s/bug72114.php on line %d ++Done + + +From 4dd03651f3c90a754600e9b76e33c9481bd9e720 Mon Sep 17 00:00:00 2001 +From: Remi Collet +Date: Wed, 25 May 2016 16:17:12 +0200 +Subject: [PATCH] Skip test which is 64bits only + +Diff from test output +001+ Warning: fread(): Length parameter must be greater than 0 in ... +001- Warning: fread(): Length parameter must be no more than 2147483647 in ... +--- + ext/standard/tests/file/bug72114.phpt | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/ext/standard/tests/file/bug72114.phpt b/ext/standard/tests/file/bug72114.phpt +index 5e591ee..3cd03fd 100644 +--- a/ext/standard/tests/file/bug72114.phpt ++++ b/ext/standard/tests/file/bug72114.phpt +@@ -1,5 +1,7 @@ + --TEST-- + Bug #72114 (Integer underflow / arbitrary null write in fread/gzread) ++--SKIPIF-- ++ + --FILE-- + +Date: Sun, 15 May 2016 23:26:51 -0700 +Subject: [PATCH] Fix bug #72135 - don't create strings with lengths outside + int range + +--- + ext/standard/html.c | 50 +++++++++++++++++++++++++++----------------------- + 1 file changed, 27 insertions(+), 23 deletions(-) + +diff --git a/ext/standard/html.c b/ext/standard/html.c +index 72423b5..81d8aff 100644 +--- a/ext/standard/html.c ++++ b/ext/standard/html.c +@@ -163,7 +163,7 @@ static inline unsigned int get_next_char( + else + MB_FAILURE(pos, 4); + } +- ++ + this_char = ((c & 0x07) << 18) | ((str[pos + 1] & 0x3f) << 12) | ((str[pos + 2] & 0x3f) << 6) | (str[pos + 3] & 0x3f); + if (this_char < 0x10000 || this_char > 0x10FFFF) { /* non-shortest form or outside range */ + MB_FAILURE(pos, 4); +@@ -437,7 +437,7 @@ static enum entity_charset determine_charset(char *charset_hint TSRMLS_DC) + + if (charset_hint) { + int found = 0; +- ++ + /* now walk the charset map and look for the codeset */ + for (i = 0; charset_map[i].codeset; i++) { + if (len == strlen(charset_map[i].codeset) && strncasecmp(charset_hint, charset_map[i].codeset, len) == 0) { +@@ -545,7 +545,7 @@ static inline unsigned char unimap_bsearch(const uni_to_enc *table, unsigned cod + return 0; + + code_key = (unsigned short) code_key_a; +- ++ + while (l <= h) { + m = l + (h - l) / 2; + if (code_key < m->un_code_point) +@@ -571,7 +571,7 @@ static inline int map_from_unicode(unsigned code, enum entity_charset charset, u + /* identity mapping of code points to unicode */ + if (code > 0xFF) { + return FAILURE; +- } ++ } + *res = code; + break; + +@@ -590,7 +590,7 @@ static inline int map_from_unicode(unsigned code, enum entity_charset charset, u + return FAILURE; + } + break; +- ++ + case cs_8859_15: + if (code < 0xA4 || (code > 0xBE && code <= 0xFF)) { + *res = code; +@@ -634,7 +634,7 @@ static inline int map_from_unicode(unsigned code, enum entity_charset charset, u + case cs_cp866: + table = unimap_cp866; + table_size = sizeof(unimap_cp866) / sizeof(*unimap_cp866); +- ++ + table_over_7F: + if (code <= 0x7F) { + *res = code; +@@ -710,7 +710,7 @@ static inline int unicode_cp_is_allowed(unsigned uni_cp, int document_type) + * Not sure this is the relevant part for HTML 5, though. I opted to + * disallow the characters that would result in a parse error when + * preprocessing of the input stream. See also section 8.1.3. +- * ++ * + * It's unclear if XHTML 1.0 allows C1 characters. I'll opt to apply to + * XHTML 1.0 the same rules as for XML 1.0. + * See . +@@ -774,7 +774,7 @@ static inline int numeric_entity_is_allowed(unsigned uni_cp, int document_type) + /* {{{ process_numeric_entity + * Auxiliary function to traverse_for_entities. + * On input, *buf should point to the first character after # and on output, it's the last +- * byte read, no matter if there was success or insuccess. ++ * byte read, no matter if there was success or insuccess. + */ + static inline int process_numeric_entity(const char **buf, unsigned *code_point) + { +@@ -784,7 +784,7 @@ static inline int process_numeric_entity(const char **buf, unsigned *code_point) + + if (hexadecimal && (**buf != '\0')) + (*buf)++; +- ++ + /* strtol allows whitespace and other stuff in the beginning + * we're not interested */ + if ((hexadecimal && !isxdigit(**buf)) || +@@ -969,7 +969,7 @@ static void traverse_for_entities( + goto invalid_code; + + /* are we allowed to decode this entity in this document type? +- * HTML 5 is the only that has a character that cannot be used in ++ * HTML 5 is the only that has a character that cannot be used in + * a numeric entity but is allowed literally (U+000D). The + * unoptimized version would be ... || !numeric_entity_is_allowed(code) */ + if (!unicode_cp_is_allowed(code, doctype) || +@@ -996,9 +996,9 @@ static void traverse_for_entities( + } + } + } +- ++ + assert(*next == ';'); +- ++ + if (((code == '\'' && !(flags & ENT_HTML_QUOTE_SINGLE)) || + (code == '"' && !(flags & ENT_HTML_QUOTE_DOUBLE))) + /* && code2 == '\0' always true for current maps */) +@@ -1026,7 +1026,7 @@ static void traverse_for_entities( + *(q++) = *p; + } + } +- ++ + *q = '\0'; + *retlen = (size_t)(q - ret); + } +@@ -1066,7 +1066,7 @@ static entity_table_opt determine_entity_table(int all, int doctype) + entity_table_opt retval = {NULL}; + + assert(!(doctype == ENT_HTML_DOC_XML1 && all)); +- ++ + if (all) { + retval.ms_table = (doctype == ENT_HTML_DOC_HTML5) ? + entity_ms_table_html5 : entity_ms_table_html4; +@@ -1111,13 +1111,13 @@ PHPAPI char *php_unescape_html_entities(unsigned char *old, size_t oldlen, size_ + if (retlen == 0) { + goto empty_source; + } +- ++ + inverse_map = unescape_inverse_map(all, flags); +- ++ + /* replace numeric entities */ + traverse_for_entities(old, oldlen, ret, &retlen, all, flags, inverse_map, charset); + +-empty_source: ++empty_source: + *newlen = retlen; + return ret; + } +@@ -1141,7 +1141,7 @@ static inline void find_entity_for_char( + { + unsigned stage1_idx = ENT_STAGE1_INDEX(k); + const entity_stage3_row *c; +- ++ + if (stage1_idx > 0x1D) { + *entity = NULL; + *entity_len = 0; +@@ -1162,7 +1162,7 @@ static inline void find_entity_for_char( + if (!(*cursor < oldlen)) + goto no_suitable_2nd; + +- next_char = get_next_char(charset, old, oldlen, cursor, &status); ++ next_char = get_next_char(charset, old, oldlen, cursor, &status); + + if (status == FAILURE) + goto no_suitable_2nd; +@@ -1187,7 +1187,7 @@ static inline void find_entity_for_char( + *entity = (const unsigned char *) + c->data.multicodepoint_table[0].leading_entry.default_entity; + *entity_len = c->data.multicodepoint_table[0].leading_entry.default_entity_len; +- } ++ } + } + /* }}} */ + +@@ -1255,7 +1255,7 @@ PHPAPI char *php_escape_html_entities_ex(unsigned char *old, size_t oldlen, size + + /* initial estimate */ + if (oldlen < 64) { +- maxlen = 128; ++ maxlen = 128; + } else { + maxlen = 2 * oldlen; + if (maxlen < oldlen) { +@@ -1444,6 +1444,10 @@ static void php_html_entities(INTERNAL_FUNCTION_PARAMETERS, int all) + } + + replaced = php_escape_html_entities_ex(str, str_len, &new_len, all, (int) flags, hint_charset, double_encode TSRMLS_CC); ++ if (new_len > INT_MAX) { ++ efree(replaced); ++ RETURN_FALSE; ++ } + RETVAL_STRINGL(replaced, (int)new_len, 0); + } + /* }}} */ +@@ -1577,7 +1581,7 @@ static inline void write_s3row_data( + } else { + spe_cp = uni_cp; + } +- ++ + written_k2 = write_octet_sequence(&key[written_k1], charset, spe_cp); + memcpy(&entity[1], mcpr[i].normal_entry.entity, l); + entity[l + 1] = ';'; +@@ -1615,7 +1619,7 @@ PHP_FUNCTION(get_html_translation_table) + LIMIT_ALL(all, doctype, charset); + + array_init(return_value); +- ++ + entity_table = determine_entity_table(all, doctype); + if (all && !CHARSET_UNICODE_COMPAT(charset)) { + to_uni_table = enc_to_uni_index[charset]; + + +From e9559131152ab0fa89737db11ebe8f43e1435b96 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev +Date: Tue, 24 May 2016 15:52:15 -0700 +Subject: [PATCH] Better fix for bug #72135 + +--- + ext/standard/html.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/ext/standard/html.c b/ext/standard/html.c +index 81d8aff..c5fd4b8 100644 +--- a/ext/standard/html.c ++++ b/ext/standard/html.c +@@ -1423,6 +1423,11 @@ PHPAPI char *php_escape_html_entities_ex(unsigned char *old, size_t oldlen, size + } + replaced[len] = '\0'; + *newlen = len; ++ if(len > INT_MAX) { ++ zend_error_noreturn(E_ERROR, "Escaped string is too long"); ++ efree(replaced); ++ return NULL; ++ } + + return replaced; + } +@@ -1444,10 +1449,6 @@ static void php_html_entities(INTERNAL_FUNCTION_PARAMETERS, int all) + } + + replaced = php_escape_html_entities_ex(str, str_len, &new_len, all, (int) flags, hint_charset, double_encode TSRMLS_CC); +- if (new_len > INT_MAX) { +- efree(replaced); +- RETURN_FALSE; +- } + RETVAL_STRINGL(replaced, (int)new_len, 0); + } + /* }}} */ diff --git a/bug72241.patch b/bug72241.patch new file mode 100644 index 0000000..c4b5492 --- /dev/null +++ b/bug72241.patch @@ -0,0 +1,46 @@ +Backported from 5.5 for 5.4 by Remi Collet + + +From 97eff7eb57fc2320c267a949cffd622c38712484 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev +Date: Sun, 22 May 2016 17:49:02 -0700 +Subject: [PATCH] Fix bug #72241: get_icu_value_internal out-of-bounds read + +--- + ext/intl/locale/locale_methods.c | 235 ++++++++++++++++++++------------------- + ext/intl/tests/bug72241.phpt | 14 +++ + 2 files changed, 132 insertions(+), 117 deletions(-) + create mode 100644 ext/intl/tests/bug72241.phpt + +diff --git a/ext/intl/locale/locale_methods.c b/ext/intl/locale/locale_methods.c +index c8159bc..31f60b3 100644 +--- a/ext/intl/locale/locale_methods.c ++++ b/ext/intl/locale/locale_methods.c +@@ -329,6 +329,7 @@ static char* get_icu_value_internal( const char* loc_name , char* tag_name, int* + if( U_FAILURE( status ) ) { + if( status == U_BUFFER_OVERFLOW_ERROR ) { + status = U_ZERO_ERROR; ++ buflen++; /* add space for \0 */ + continue; + } + +diff --git a/ext/intl/tests/bug72241.phpt b/ext/intl/tests/bug72241.phpt +new file mode 100644 +index 0000000..397e1e7 +--- /dev/null ++++ b/ext/intl/tests/bug72241.phpt +@@ -0,0 +1,14 @@ ++--TEST-- ++Bug #72241: get_icu_value_internal out-of-bounds read ++--SKIPIF-- ++ ++--FILE-- ++ +Date: Mon, 9 May 2016 22:17:20 -0700 +Subject: [PATCH] Add check for string overflow to all string add operations + +--- + Zend/zend_operators.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c +index e0812fc..2f1394f 100644 +--- a/Zend/zend_operators.c ++++ b/Zend/zend_operators.c +@@ -1199,6 +1199,10 @@ ZEND_API int add_char_to_string(zval *result, const zval *op1, const zval *op2) + int length = Z_STRLEN_P(op1) + 1; + char *buf; + ++ if (UNEXPECTED(length < 0)) { ++ zend_error(E_ERROR, "String size overflow"); ++ } ++ + if (IS_INTERNED(Z_STRVAL_P(op1))) { + buf = (char *) emalloc(length + 1); + memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1)); +@@ -1218,6 +1222,9 @@ ZEND_API int add_string_to_string(zval *result, const zval *op1, const zval *op2 + int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2); + char *buf; + ++ if (UNEXPECTED(length < 0)) { ++ zend_error(E_ERROR, "String size overflow"); ++ } + if (IS_INTERNED(Z_STRVAL_P(op1))) { + buf = (char *) emalloc(length+1); + memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1)); diff --git a/failed.txt b/failed.txt index fdcedb8..2e625d6 100644 --- a/failed.txt +++ b/failed.txt @@ -1,11 +1,11 @@ -===== 5.5.45-8 (2016-04-27) +===== 5.5.45-9 (2016-05-29) $ grep -r 'Tests failed' /var/lib/mock/scl54*/build.log /var/lib/mock/scl54el6x/build.log:Tests failed : 1 /var/lib/mock/scl54el7x/build.log:Tests failed : 0 /var/lib/mock/scl54fc21x/build.log:Tests failed : 1 -/var/lib/mock/scl54fc22x/build.log:Tests failed : 1 +/var/lib/mock/scl54fc22x/build.log:Tests failed : 2 /var/lib/mock/scl54fc23x/build.log:Tests failed : 2 /var/lib/mock/scl54fc24x/build.log:Tests failed : 2 @@ -13,5 +13,8 @@ f23, f24 Bug #64802: openssl_x509_parse fails to parse subject properly in some cases [ext/openssl/tests/bug64802.phpt] f21, f22, f23, f24 Test strptime() function : basic functionality [ext/standard/tests/time/strptime_basic.phpt] +f22 + file_get_contents() test using offset parameter out of range [ext/standard/tests/file/file_get_contents_error001.phpt] el6 Bug #32001 (xml_parse*() goes into infinite loop when autodetection in effect), using UTF-* [ext/xml/tests/bug32001.phpt] + diff --git a/php.spec b/php.spec index 9ab782e..6f3cd34 100644 --- a/php.spec +++ b/php.spec @@ -119,7 +119,7 @@ Summary: PHP scripting language for creating dynamic web sites Name: %{?scl_prefix}php Version: 5.4.45 -Release: 8%{?dist} +Release: 9%{?dist} # All files licensed under PHP version 3.01, except # Zend is licensed under Zend # TSRM is licensed under BSD @@ -206,6 +206,11 @@ Patch223: bug72061.patch Patch224: bug72093.patch Patch225: bug72094.patch Patch226: bug72099.patch +Patch227: bug71331.patch +Patch228: bug72114.patch +Patch229: bugoverflow.patch +Patch230: bug72135.patch +Patch231: bug72241.patch # Fixes for tests (300+) # Backported from 5.5 @@ -870,6 +875,11 @@ support for using the enchant library to PHP. %patch224 -p1 -b .bug72093 %patch225 -p1 -b .bug72094 %patch226 -p1 -b .bug72099 +%patch227 -p1 -b .bug71331 +%patch228 -p1 -b .bug72114 +%patch229 -p1 -b .bugoverflow +%patch230 -p1 -b .bug72135 +%patch231 -p1 -b .bug72241 # Fixes for tests %patch300 -p1 -b .datetests1 @@ -1693,6 +1703,17 @@ EOF %changelog +* Sun May 29 2016 Remi Collet 5.4.45-9 +- Fix #71331: Uninitialized pointer in phar_make_dirstream + CVE-2016-4343 +- Fix #72114: int/size_t confusion in fread + CVE-2016-5096 +- Add check for string overflow to all string add operations +- Fix #72135: don't create strings with lengths outside int range + CVE-2016-5094 +- Fix #72241: get_icu_value_internal out-of-bounds read + CVE-2016-5093 + * Tue Apr 26 2016 Remi Collet 5.4.45-8 - Fix #64938: libxml_disable_entity_loader setting is shared between threads CVE-2015-8866 -- cgit