From 9649ca1630433473a307d015ba1a79a4a7a779f5 Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Thu, 14 Jan 2016 22:58:40 -0800 Subject: 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 75cf049ade..94958a26aa 100644 --- a/ext/phar/dirstream.c +++ b/ext/phar/dirstream.c @@ -207,6 +207,7 @@ static php_stream *phar_make_dirstream(char *dir, HashTable *manifest TSRMLS_DC) zend_hash_internal_pointer_reset(manifest); while (FAILURE != zend_hash_has_more_elements(manifest)) { + keylen = 0; if (HASH_KEY_NON_EXISTENT == zend_hash_get_current_key_ex(manifest, &key, &keylen, &unused, 0, NULL)) { break; } @@ -214,7 +215,7 @@ static php_stream *phar_make_dirstream(char *dir, HashTable *manifest TSRMLS_DC) 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 3a4bd491f8..bf19e08ac0 100644 --- a/ext/phar/tar.c +++ b/ext/phar/tar.c @@ -356,7 +356,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/ext/phar/tests/bug71331.phpt b/ext/phar/tests/bug71331.phpt new file mode 100644 index 0000000000..106fd540fc --- /dev/null +++ b/ext/phar/tests/bug71331.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #71331 (Uninitialized pointer in phar_make_dirstream()) +--SKIPIF-- + +--FILE-- + +DONE +--EXPECTF-- +Fatal error: Uncaught exception 'UnexpectedValueException' with message 'phar error: "%s/bug71331.tar" is a corrupted tar file (invalid entry size)' in %s/bug71331.php:2 +Stack trace: +#0 %s/bug71331.php(2): PharData->__construct('%s') +#1 {main} + thrown in %s/bug71331.php on line 2 \ No newline at end of file diff --git a/ext/phar/tests/bug71331.tar b/ext/phar/tests/bug71331.tar new file mode 100644 index 0000000000..14eec28781 Binary files /dev/null and b/ext/phar/tests/bug71331.tar differ -- cgit v1.2.1 From 95ed19ae28009aa7b3ed42d5760478de82640560 Mon Sep 17 00:00:00 2001 From: Julien Pauli Date: Mon, 2 May 2016 16:52:58 +0200 Subject: Updated NEWS --- NEWS | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index 298023e18d..a7e00962c8 100644 --- a/NEWS +++ b/NEWS @@ -4,27 +4,30 @@ PHP NEWS ??? 2016, PHP 5.5.36 +- Phar: + . Fixed bug #71331 (Uninitialized pointer in phar_make_dirstream()). + (CVE-2016-4343) (Stas) 28 Apr 2016, PHP 5.5.35 - BCMath: - . Fix bug #72093 (bcpowmod accepts negative scale and corrupts _one_ + . Fixed bug #72093 (bcpowmod accepts negative scale and corrupts _one_ definition). (Stas) - Exif: - . Fix bug #72094 (Out of bounds heap read access in exif header + . Fixed bug #72094 (Out of bounds heap read access in exif header processing). (Stas) - GD: - . Fix bug #71912 (libgd: signedness vulnerability) (CVE-2016-3074). (Stas) + . Fixed bug #71912 (libgd: signedness vulnerability) (CVE-2016-3074). (Stas) - Intl: - . Fix bug #72061 (Out-of-bounds reads in zif_grapheme_stripos with negative + . Fixed bug #72061 (Out-of-bounds reads in zif_grapheme_stripos with negative offset). (Stas) - XML: - . Fix bug #72099 (xml_parse_into_struct segmentation fault). (Stas) + . Fixed bug #72099 (xml_parse_into_struct segmentation fault). (Stas) 31 Mar 2016, PHP 5.5.34 -- cgit v1.2.1 From abd159cce48f3e34f08e4751c568e09677d5ec9c Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Mon, 9 May 2016 21:55:29 -0700 Subject: 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 0abc022ca6..e39c84f1cd 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -1758,6 +1758,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 0000000000..5e591ee478 --- /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 -- cgit v1.2.1 From 41fc3c76e97a36ff3b505da7d704ca17bb171fdf Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Mon, 9 May 2016 22:17:20 -0700 Subject: 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 e0812fccc4..2f1394f78d 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -1254,6 +1254,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)); @@ -1273,6 +1277,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)); -- cgit v1.2.1 From 0da8b8b801f9276359262f1ef8274c7812d3dfda Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Sun, 15 May 2016 23:26:51 -0700 Subject: 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 72423b59f0..81d8aff9e9 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 @@ det_charset: 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 @@ invalid_code: *(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 @@ no_suitable_2nd: *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]; -- cgit v1.2.1 From 97eff7eb57fc2320c267a949cffd622c38712484 Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Sun, 22 May 2016 17:49:02 -0700 Subject: 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 c8159bcd5a..31f60b39a4 100644 --- a/ext/intl/locale/locale_methods.c +++ b/ext/intl/locale/locale_methods.c @@ -65,26 +65,26 @@ ZEND_EXTERN_MODULE_GLOBALS( intl ) */ static const char * const LOC_GRANDFATHERED[] = { "art-lojban", "i-klingon", "i-lux", "i-navajo", "no-bok", "no-nyn", - "cel-gaulish", "en-GB-oed", "i-ami", - "i-bnn", "i-default", "i-enochian", - "i-mingo", "i-pwn", "i-tao", + "cel-gaulish", "en-GB-oed", "i-ami", + "i-bnn", "i-default", "i-enochian", + "i-mingo", "i-pwn", "i-tao", "i-tay", "i-tsu", "sgn-BE-fr", "sgn-BE-nl", "sgn-CH-de", "zh-cmn", "zh-cmn-Hans", "zh-cmn-Hant", "zh-gan" , "zh-guoyu", "zh-hakka", "zh-min", - "zh-min-nan", "zh-wuu", "zh-xiang", + "zh-min-nan", "zh-wuu", "zh-xiang", "zh-yue", NULL }; /* Based on IANA registry at the time of writing this code * This array lists the preferred values for the grandfathered tags if applicable -* This is in sync with the array LOC_GRANDFATHERED +* This is in sync with the array LOC_GRANDFATHERED * e.g. the offsets of the grandfathered tags match the offset of the preferred value */ static const int LOC_PREFERRED_GRANDFATHERED_LEN = 6; static const char * const LOC_PREFERRED_GRANDFATHERED[] = { "jbo", "tlh", "lb", - "nv", "nb", "nn", + "nv", "nb", "nn", NULL }; @@ -122,7 +122,7 @@ static int16_t findOffset(const char* const* list, const char* key) /*}}}*/ static char* getPreferredTag(const char* gf_tag) -{ +{ char* result = NULL; int grOffset = 0; @@ -141,15 +141,15 @@ static char* getPreferredTag(const char* gf_tag) } /* {{{ -* returns the position of next token for lookup +* returns the position of next token for lookup * or -1 if no token -* strtokr equivalent search for token in reverse direction +* strtokr equivalent search for token in reverse direction */ static int getStrrtokenPos(char* str, int savedPos) { int result =-1; int i; - + for(i=savedPos-1; i>=0; i--) { if(isIDSeparator(*(str+i)) ){ /* delimiter found; check for singleton */ @@ -171,7 +171,7 @@ static int getStrrtokenPos(char* str, int savedPos) /* }}} */ /* {{{ -* returns the position of a singleton if present +* returns the position of a singleton if present * returns -1 if no singleton * strtok equivalent search for singleton */ @@ -180,7 +180,7 @@ static int getSingletonPos(const char* str) int result =-1; int i=0; int len = 0; - + if( str && ((len=strlen(str))>0) ){ for( i=0; ic, (s)->len, 0) -/* {{{ proto static string Locale::composeLocale($array) -* Creates a locale by combining the parts of locale-ID passed +/* {{{ proto static string Locale::composeLocale($array) +* Creates a locale by combining the parts of locale-ID passed * }}} */ -/* {{{ proto static string compose_locale($array) -* Creates a locale by combining the parts of locale-ID passed +/* {{{ proto static string compose_locale($array) +* Creates a locale by combining the parts of locale-ID passed * }}} */ PHP_FUNCTION(locale_compose) { @@ -920,7 +921,7 @@ PHP_FUNCTION(locale_compose) RETURN_FALSE; /* Check for grandfathered first */ - result = append_key_value(loc_name, hash_arr, LOC_GRANDFATHERED_LANG_TAG); + result = append_key_value(loc_name, hash_arr, LOC_GRANDFATHERED_LANG_TAG); if( result == SUCCESS){ RETURN_SMART_STR(loc_name); } @@ -929,7 +930,7 @@ PHP_FUNCTION(locale_compose) } /* Not grandfathered */ - result = append_key_value(loc_name, hash_arr , LOC_LANG_TAG); + result = append_key_value(loc_name, hash_arr , LOC_LANG_TAG); if( result == LOC_NOT_FOUND ){ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "locale_compose: parameter array does not contain 'language' tag.", 0 TSRMLS_CC ); @@ -947,11 +948,11 @@ PHP_FUNCTION(locale_compose) } /* Script */ - result = append_key_value(loc_name, hash_arr , LOC_SCRIPT_TAG); + result = append_key_value(loc_name, hash_arr , LOC_SCRIPT_TAG); if( !handleAppendResult( result, loc_name TSRMLS_CC)){ RETURN_FALSE; } - + /* Region */ result = append_key_value( loc_name, hash_arr , LOC_REGION_TAG); if( !handleAppendResult( result, loc_name TSRMLS_CC)){ @@ -959,7 +960,7 @@ PHP_FUNCTION(locale_compose) } /* Variant */ - result = append_multiple_key_values( loc_name, hash_arr , LOC_VARIANT_TAG TSRMLS_CC); + result = append_multiple_key_values( loc_name, hash_arr , LOC_VARIANT_TAG TSRMLS_CC); if( !handleAppendResult( result, loc_name TSRMLS_CC)){ RETURN_FALSE; } @@ -985,16 +986,16 @@ static char* get_private_subtags(const char* loc_name) { char* result =NULL; int singletonPos = 0; - int len =0; + int len =0; const char* mod_loc_name =NULL; if( loc_name && (len = strlen(loc_name)>0 ) ){ - mod_loc_name = loc_name ; + mod_loc_name = loc_name ; len = strlen(mod_loc_name); while( (singletonPos = getSingletonPos(mod_loc_name))!= -1){ - if( singletonPos!=-1){ - if( (*(mod_loc_name+singletonPos)=='x') || (*(mod_loc_name+singletonPos)=='X') ){ + if( singletonPos!=-1){ + if( (*(mod_loc_name+singletonPos)=='x') || (*(mod_loc_name+singletonPos)=='X') ){ /* private subtag start found */ if( singletonPos + 2 == len){ /* loc_name ends with '-x-' ; return NULL */ @@ -1019,7 +1020,7 @@ static char* get_private_subtags(const char* loc_name) } /* end of while */ } - + return result; } /* }}} */ @@ -1044,20 +1045,20 @@ static int add_array_entry(const char* loc_name, zval* hash_arr, char* key_name } else { key_value = get_icu_value_internal( loc_name , key_name , &result,1 ); } - if( (strcmp(key_name , LOC_PRIVATE_TAG)==0) || + if( (strcmp(key_name , LOC_PRIVATE_TAG)==0) || ( strcmp(key_name , LOC_VARIANT_TAG)==0) ){ if( result > 0 && key_value){ /* Tokenize on the "_" or "-" */ - token = php_strtok_r( key_value , DELIMITER ,&last_ptr); + token = php_strtok_r( key_value , DELIMITER ,&last_ptr); if( cur_key_name ){ efree( cur_key_name); } cur_key_name = (char*)ecalloc( 25, 25); - sprintf( cur_key_name , "%s%d", key_name , cnt++); + sprintf( cur_key_name , "%s%d", key_name , cnt++); add_assoc_string( hash_arr, cur_key_name , token ,TRUE ); /* tokenize on the "_" or "-" and stop at singleton if any */ while( (token = php_strtok_r(NULL , DELIMITER , &last_ptr)) && (strlen(token)>1) ){ - sprintf( cur_key_name , "%s%d", key_name , cnt++); + sprintf( cur_key_name , "%s%d", key_name , cnt++); add_assoc_string( hash_arr, cur_key_name , token , TRUE ); } /* @@ -1077,16 +1078,16 @@ static int add_array_entry(const char* loc_name, zval* hash_arr, char* key_name } /*if( key_name != LOC_PRIVATE_TAG && key_value){*/ if( key_value){ - efree(key_value); + efree(key_value); } return cur_result; } /* }}} */ -/* {{{ proto static array Locale::parseLocale($locale) +/* {{{ proto static array Locale::parseLocale($locale) * parses a locale-id into an array the different parts of it }}} */ -/* {{{ proto static array parse_locale($locale) +/* {{{ proto static array parse_locale($locale) * parses a locale-id into an array the different parts of it */ PHP_FUNCTION(locale_parse) @@ -1144,7 +1145,7 @@ PHP_FUNCTION(locale_get_all_variants) char* saved_ptr = NULL; intl_error_reset( NULL TSRMLS_CC ); - + if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s", &loc_name, &loc_name_len ) == FAILURE) { @@ -1162,15 +1163,15 @@ PHP_FUNCTION(locale_get_all_variants) array_init( return_value ); /* If the locale is grandfathered, stop, no variants */ - if( findOffset( LOC_GRANDFATHERED , loc_name ) >= 0 ){ + if( findOffset( LOC_GRANDFATHERED , loc_name ) >= 0 ){ /* ("Grandfathered Tag. No variants."); */ } - else { + else { /* Call ICU variant */ variant = get_icu_value_internal( loc_name , LOC_VARIANT_TAG , &result ,0); if( result > 0 && variant){ /* Tokenize on the "_" or "-" */ - token = php_strtok_r( variant , DELIMITER , &saved_ptr); + token = php_strtok_r( variant , DELIMITER , &saved_ptr); add_next_index_stringl( return_value, token , strlen(token) ,TRUE ); /* tokenize on the "_" or "-" and stop at singleton if any */ while( (token = php_strtok_r(NULL , DELIMITER, &saved_ptr)) && (strlen(token)>1) ){ @@ -1181,7 +1182,7 @@ PHP_FUNCTION(locale_get_all_variants) efree( variant ); } } - + } /* }}} */ @@ -1220,11 +1221,11 @@ static int strToMatch(const char* str ,char *retstr) /* }}} */ /* {{{ proto static boolean Locale::filterMatches(string $langtag, string $locale[, bool $canonicalize]) -* Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm +* Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm */ /* }}} */ /* {{{ proto boolean locale_filter_matches(string $langtag, string $locale[, bool $canonicalize]) -* Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm +* Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm */ PHP_FUNCTION(locale_filter_matches) { @@ -1243,13 +1244,13 @@ PHP_FUNCTION(locale_filter_matches) char* cur_lang_tag = NULL; char* cur_loc_range = NULL; - zend_bool boolCanonical = 0; + zend_bool boolCanonical = 0; UErrorCode status = U_ZERO_ERROR; intl_error_reset( NULL TSRMLS_CC ); - + if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "ss|b", - &lang_tag, &lang_tag_len , &loc_range , &loc_range_len , + &lang_tag, &lang_tag_len , &loc_range , &loc_range_len , &boolCanonical) == FAILURE) { intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, @@ -1270,7 +1271,7 @@ PHP_FUNCTION(locale_filter_matches) /* canonicalize loc_range */ can_loc_range=get_icu_value_internal( loc_range , LOC_CANONICALIZE_TAG , &result , 0); if( result ==0) { - intl_error_set( NULL, status, + intl_error_set( NULL, status, "locale_filter_matches : unable to canonicalize loc_range" , 0 TSRMLS_CC ); RETURN_FALSE; } @@ -1278,7 +1279,7 @@ PHP_FUNCTION(locale_filter_matches) /* canonicalize lang_tag */ can_lang_tag = get_icu_value_internal( lang_tag , LOC_CANONICALIZE_TAG , &result , 0); if( result ==0) { - intl_error_set( NULL, status, + intl_error_set( NULL, status, "locale_filter_matches : unable to canonicalize lang_tag" , 0 TSRMLS_CC ); RETURN_FALSE; } @@ -1306,11 +1307,11 @@ PHP_FUNCTION(locale_filter_matches) /* check if prefix */ token = strstr( cur_lang_tag , cur_loc_range ); - + if( token && (token==cur_lang_tag) ){ /* check if the char. after match is SEPARATOR */ chrcheck = token + (strlen(cur_loc_range)); - if( isIDSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){ + if( isIDSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){ if( cur_lang_tag){ efree( cur_lang_tag ); } @@ -1346,7 +1347,7 @@ PHP_FUNCTION(locale_filter_matches) else{ /* Convert to lower case for case-insensitive comparison */ cur_lang_tag = ecalloc( 1, strlen(lang_tag ) + 1); - + result = strToMatch( lang_tag , cur_lang_tag); if( result == 0) { efree( cur_lang_tag ); @@ -1362,11 +1363,11 @@ PHP_FUNCTION(locale_filter_matches) /* check if prefix */ token = strstr( cur_lang_tag , cur_loc_range ); - + if( token && (token==cur_lang_tag) ){ /* check if the char. after match is SEPARATOR */ chrcheck = token + (strlen(cur_loc_range)); - if( isIDSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){ + if( isIDSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){ if( cur_lang_tag){ efree( cur_lang_tag ); } @@ -1393,7 +1394,7 @@ PHP_FUNCTION(locale_filter_matches) static void array_cleanup( char* arr[] , int arr_size) { int i=0; - for( i=0; i< arr_size; i++ ){ + for( i=0; i< arr_size; i++ ){ if( arr[i*2] ){ efree( arr[i*2]); } @@ -1403,7 +1404,7 @@ static void array_cleanup( char* arr[] , int arr_size) #define LOOKUP_CLEAN_RETURN(value) array_cleanup(cur_arr, cur_arr_len); return (value) /* {{{ -* returns the lookup result to lookup_loc_range_src_php +* returns the lookup result to lookup_loc_range_src_php * internal function */ static char* lookup_loc_range(const char* loc_range, HashTable* hash_arr, int canonicalize TSRMLS_DC) @@ -1427,7 +1428,7 @@ static char* lookup_loc_range(const char* loc_range, HashTable* hash_arr, int ca for(zend_hash_internal_pointer_reset(hash_arr); zend_hash_has_more_elements(hash_arr) == SUCCESS; zend_hash_move_forward(hash_arr)) { - + if (zend_hash_get_current_data(hash_arr, (void**)&ele_value) == FAILURE) { /* Should never actually fail since the key is known to exist.*/ continue; @@ -1436,7 +1437,7 @@ static char* lookup_loc_range(const char* loc_range, HashTable* hash_arr, int ca /* element value is not a string */ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: locale array element is not a string", 0 TSRMLS_CC); LOOKUP_CLEAN_RETURN(NULL); - } + } cur_arr[cur_arr_len*2] = estrndup(Z_STRVAL_PP(ele_value), Z_STRLEN_PP(ele_value)); result = strToMatch(Z_STRVAL_PP(ele_value), cur_arr[cur_arr_len*2]); if(result == 0) { @@ -1444,12 +1445,12 @@ static char* lookup_loc_range(const char* loc_range, HashTable* hash_arr, int ca LOOKUP_CLEAN_RETURN(NULL); } cur_arr[cur_arr_len*2+1] = Z_STRVAL_PP(ele_value); - cur_arr_len++ ; + cur_arr_len++ ; } /* end of for */ /* Canonicalize array elements */ if(canonicalize) { - for(i=0; i 0) { - for(i=0; i< cur_arr_len; i++){ - if(cur_arr[i*2] != NULL && strlen(cur_arr[i*2]) == saved_pos && strncmp(cur_loc_range, cur_arr[i*2], saved_pos) == 0) { + for(i=0; i< cur_arr_len; i++){ + if(cur_arr[i*2] != NULL && strlen(cur_arr[i*2]) == saved_pos && strncmp(cur_loc_range, cur_arr[i*2], saved_pos) == 0) { /* Match found */ return_value = estrdup(canonicalize?cur_arr[i*2]:cur_arr[i*2+1]); efree(cur_loc_range); @@ -1515,14 +1516,14 @@ static char* lookup_loc_range(const char* loc_range, HashTable* hash_arr, int ca } /* }}} */ -/* {{{ proto string Locale::lookup(array $langtag, string $locale[, bool $canonicalize[, string $default = null]]) +/* {{{ proto string Locale::lookup(array $langtag, string $locale[, bool $canonicalize[, string $default = null]]) * Searchs the items in $langtag for the best match to the language -* range +* range */ /* }}} */ /* {{{ proto string locale_lookup(array $langtag, string $locale[, bool $canonicalize[, string $default = null]]) * Searchs the items in $langtag for the best match to the language -* range +* range */ PHP_FUNCTION(locale_lookup) { @@ -1552,8 +1553,8 @@ PHP_FUNCTION(locale_lookup) if( !hash_arr || zend_hash_num_elements( hash_arr ) == 0 ) { RETURN_EMPTY_STRING(); - } - + } + result = lookup_loc_range(loc_range, hash_arr, boolCanonical TSRMLS_CC); if(result == NULL || result[0] == '\0') { if( fallback_loc ) { @@ -1590,10 +1591,10 @@ PHP_FUNCTION(locale_accept_from_http) "locale_accept_from_http: unable to parse input parameters", 0 TSRMLS_CC ); RETURN_FALSE; } - + available = ures_openAvailableLocales(NULL, &status); INTL_CHECK_STATUS(status, "locale_accept_from_http: failed to retrieve locale list"); - len = uloc_acceptLanguageFromHTTP(resultLocale, INTL_MAX_LOCALE_LEN, + len = uloc_acceptLanguageFromHTTP(resultLocale, INTL_MAX_LOCALE_LEN, &outResult, http_accept, available, &status); uenum_close(available); INTL_CHECK_STATUS(status, "locale_accept_from_http: failed to find acceptable locale"); diff --git a/ext/intl/tests/bug72241.phpt b/ext/intl/tests/bug72241.phpt new file mode 100644 index 0000000000..397e1e7834 --- /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, 23 May 2016 00:28:02 -0700 Subject: Fixed bug #72227: imagescale out-of-bounds read Ported from https://github.com/libgd/libgd/commit/4f65a3e4eedaffa1efcf9ee1eb08f0b504fbc31a --- ext/gd/libgd/gd_interpolation.c | 16 ++++++++-------- ext/gd/tests/bug72227.phpt | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 ext/gd/tests/bug72227.phpt diff --git a/ext/gd/libgd/gd_interpolation.c b/ext/gd/libgd/gd_interpolation.c index 6b7360a6de..a017498383 100644 --- a/ext/gd/libgd/gd_interpolation.c +++ b/ext/gd/libgd/gd_interpolation.c @@ -39,8 +39,8 @@ downscaling using the fixed point implementations are usually much faster than the existing gdImageCopyResampled while having a similar or better quality. - - For image rotations, the optimized versions have a lazy antialiasing for + + For image rotations, the optimized versions have a lazy antialiasing for the edges of the images. For a much better antialiased result, the affine function is recommended. */ @@ -633,7 +633,7 @@ static inline int _color_blend (const int dst, const int src) } } -static inline int _setEdgePixel(const gdImagePtr src, unsigned int x, unsigned int y, gdFixed coverage, const int bgColor) +static inline int _setEdgePixel(const gdImagePtr src, unsigned int x, unsigned int y, gdFixed coverage, const int bgColor) { const gdFixed f_127 = gd_itofx(127); register int c = src->tpixels[y][x]; @@ -934,9 +934,6 @@ static inline LineContribType *_gdContributionsCalc(unsigned int line_size, unsi double dTotalWeight = 0.0; int iSrc; - res->ContribRow[u].Left = iLeft; - res->ContribRow[u].Right = iRight; - /* Cut edge points to fit in filter window in case of spill-off */ if (iRight - iLeft + 1 > windows_size) { if (iLeft < ((int)src_size - 1 / 2)) { @@ -946,6 +943,9 @@ static inline LineContribType *_gdContributionsCalc(unsigned int line_size, unsi } } + res->ContribRow[u].Left = iLeft; + res->ContribRow[u].Right = iRight; + for (iSrc = iLeft; iSrc <= iRight; iSrc++) { dTotalWeight += (res->ContribRow[u].Weights[iSrc-iLeft] = scale_f_d * (*pFilter)(scale_f_d * (dCenter - (double)iSrc))); } @@ -2273,7 +2273,7 @@ int gdTransformAffineGetImage(gdImagePtr *dst, if (!src->trueColor) { gdImagePaletteToTrueColor(src); } - + /* Translate to dst origin (0,0) */ gdAffineTranslate(m, -bbox.x, -bbox.y); gdAffineConcat(m, affine, m); @@ -2332,7 +2332,7 @@ int gdTransformAffineCopy(gdImagePtr dst, if (src->interpolation_id == GD_BILINEAR_FIXED || src->interpolation_id == GD_BICUBIC_FIXED || src->interpolation_id == GD_NEAREST_NEIGHBOUR) { interpolation_id_bak = src->interpolation_id; interpolation_bak = src->interpolation; - + gdImageSetInterpolationMethod(src, GD_BICUBIC); } diff --git a/ext/gd/tests/bug72227.phpt b/ext/gd/tests/bug72227.phpt new file mode 100644 index 0000000000..6252be7d0e --- /dev/null +++ b/ext/gd/tests/bug72227.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #72227: imagescale out-of-bounds read +--SKIPIF-- + +--FILE-- + +DONE +--EXPECT-- +DONE \ No newline at end of file -- cgit v1.2.1 From e9559131152ab0fa89737db11ebe8f43e1435b96 Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Tue, 24 May 2016 15:52:15 -0700 Subject: 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 81d8aff9e9..c5fd4b87a8 100644 --- a/ext/standard/html.c +++ b/ext/standard/html.c @@ -1423,6 +1423,11 @@ encode_amp: } 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); } /* }}} */ -- cgit v1.2.1 From f423e1bb895d64c50dc538e8cdc556324e8b8cc2 Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Tue, 24 May 2016 15:56:02 -0700 Subject: Update NEWS --- NEWS | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index a7e00962c8..f824cea0e0 100644 --- a/NEWS +++ b/NEWS @@ -2,13 +2,23 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ** PHP 5.5 is in security-only mode , please do not commit to this branch ** -??? 2016, PHP 5.5.36 +26 May 2016, PHP 5.5.36 + +- Core: + . Fixed bug #72114 (Integer underflow / arbitrary null write in + fread/gzread). (Stas) + . Fixed bug #72135 (Integer Overflow in php_html_entities). (Stas) + +- GD: + . Fixed bug ##72227 (imagescale out-of-bounds read). (Stas) + +- Intl: + . Fixed bug #72241 (get_icu_value_internal out-of-bounds read). (Stas) - Phar: . Fixed bug #71331 (Uninitialized pointer in phar_make_dirstream()). (CVE-2016-4343) (Stas) - 28 Apr 2016, PHP 5.5.35 - BCMath: -- cgit v1.2.1 From 9a826a3bd99315b7c4d4673acd3084c99eb04253 Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Tue, 24 May 2016 16:12:01 -0700 Subject: Fix memory leak in imagescale() --- NEWS | 2 +- ext/gd/libgd/gd_interpolation.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index f824cea0e0..afc6fa77d9 100644 --- a/NEWS +++ b/NEWS @@ -10,7 +10,7 @@ PHP NEWS . Fixed bug #72135 (Integer Overflow in php_html_entities). (Stas) - GD: - . Fixed bug ##72227 (imagescale out-of-bounds read). (Stas) + . Fixed bug #72227 (imagescale out-of-bounds read). (Stas) - Intl: . Fixed bug #72241 (get_icu_value_internal out-of-bounds read). (Stas) diff --git a/ext/gd/libgd/gd_interpolation.c b/ext/gd/libgd/gd_interpolation.c index a017498383..0961c08048 100644 --- a/ext/gd/libgd/gd_interpolation.c +++ b/ext/gd/libgd/gd_interpolation.c @@ -1070,12 +1070,12 @@ gdImagePtr gdImageScaleTwoPass(const gdImagePtr src, const unsigned int src_widt dst = gdImageCreateTrueColor(new_width, new_height); if (dst == NULL) { - gdFree(tmp_im); + gdImageDestroy(tmp_im); return NULL; } gdImageSetInterpolationMethod(dst, src->interpolation_id); _gdScaleVert(tmp_im, new_width, src_height, dst, new_width, new_height); - gdFree(tmp_im); + gdImageDestroy(tmp_im); return dst; } @@ -1093,7 +1093,7 @@ gdImagePtr Scale(const gdImagePtr src, const unsigned int src_width, const unsig _gdScaleHoriz(src, src_width, src_height, tmp_im, new_width, src_height); _gdScaleVert(tmp_im, new_width, src_height, dst, new_width, new_height); - gdFree(tmp_im); + gdImageDestroy(tmp_im); return dst; } -- cgit v1.2.1