Merge branch 'PHP-7.1'

* PHP-7.1:
  More int->size_t and string overflow fixes
This commit is contained in:
Stanislav Malyshev 2016-11-05 13:59:56 -07:00
commit bbdd6a65e2
10 changed files with 52 additions and 43 deletions

View file

@ -300,6 +300,19 @@ static zend_always_inline size_t zend_safe_address_guarded(size_t nmemb, size_t
return ret; return ret;
} }
/* A bit more generic version of the same */
static zend_always_inline size_t zend_safe_addmult(size_t nmemb, size_t size, size_t offset, const char *message)
{
int overflow;
size_t ret = zend_safe_address(nmemb, size, offset, &overflow);
if (UNEXPECTED(overflow)) {
zend_error_noreturn(E_ERROR, "Possible integer overflow in %s (%zu * %zu + %zu)", message, nmemb, size, offset);
return 0;
}
return ret;
}
#endif /* ZEND_MULTIPLY_H */ #endif /* ZEND_MULTIPLY_H */
/* /*

View file

@ -2677,6 +2677,14 @@ zend_strtod
} }
} }
dig_done: dig_done:
if (nd < 0) {
/* overflow */
nd = DBL_DIG + 2;
}
if (nf < 0) {
/* overflow */
nf = DBL_DIG + 2;
}
e = 0; e = 0;
if (c == 'e' || c == 'E') { if (c == 'e' || c == 'E') {
if (!nd && !nz && !nz0) { if (!nd && !nz && !nz0) {
@ -4529,7 +4537,7 @@ static void destroy_freelist(void)
} }
freelist[i] = NULL; freelist[i] = NULL;
} }
FREE_DTOA_LOCK(0) FREE_DTOA_LOCK(0)
} }
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -589,8 +589,8 @@ static PHP_FUNCTION(bzdecompress)
bzs.avail_in = source_len; bzs.avail_in = source_len;
/* in most cases bz2 offers at least 2:1 compression, so we use that as our base */ /* in most cases bz2 offers at least 2:1 compression, so we use that as our base */
dest = zend_string_safe_alloc(source_len, 2, 1, 0);
bzs.avail_out = source_len * 2; bzs.avail_out = source_len * 2;
dest = zend_string_alloc(bzs.avail_out + 1, 0);
bzs.next_out = ZSTR_VAL(dest); bzs.next_out = ZSTR_VAL(dest);
while ((error = BZ2_bzDecompress(&bzs)) == BZ_OK && bzs.avail_in > 0) { while ((error = BZ2_bzDecompress(&bzs)) == BZ_OK && bzs.avail_in > 0) {

View file

@ -1529,7 +1529,7 @@ PHP_FUNCTION(pg_connect_poll)
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_link) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_link) == FAILURE) {
return; return;
} }
if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) { if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
RETURN_FALSE; RETURN_FALSE;
} }
@ -4381,7 +4381,7 @@ PHP_FUNCTION(pg_escape_string)
break; break;
} }
to = zend_string_alloc(ZSTR_LEN(from) * 2, 0); to = zend_string_safe_alloc(ZSTR_LEN(from), 2, 0, 0);
#ifdef HAVE_PQESCAPE_CONN #ifdef HAVE_PQESCAPE_CONN
if (link) { if (link) {
if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) { if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
@ -4433,7 +4433,7 @@ PHP_FUNCTION(pg_escape_bytea)
RETURN_FALSE; RETURN_FALSE;
} }
to = (char *)PQescapeByteaConn(pgsql, (unsigned char *)from, (size_t)from_len, &to_len); to = (char *)PQescapeByteaConn(pgsql, (unsigned char *)from, (size_t)from_len, &to_len);
} else } else
#endif #endif
to = (char *)PQescapeBytea((unsigned char*)from, from_len, &to_len); to = (char *)PQescapeBytea((unsigned char*)from, from_len, &to_len);

View file

@ -199,7 +199,7 @@ static inline void spl_filesystem_object_get_file_name(spl_filesystem_object *in
if (intern->file_name) { if (intern->file_name) {
efree(intern->file_name); efree(intern->file_name);
} }
intern->file_name_len = (int)spprintf(&intern->file_name, 0, "%s%c%s", intern->file_name_len = spprintf(&intern->file_name, 0, "%s%c%s",
spl_filesystem_object_get_path(intern, NULL), spl_filesystem_object_get_path(intern, NULL),
slash, intern->u.dir.entry.d_name); slash, intern->u.dir.entry.d_name);
break; break;
@ -232,7 +232,7 @@ static void spl_filesystem_dir_open(spl_filesystem_object* intern, char *path)
int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS); int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS);
intern->type = SPL_FS_DIR; intern->type = SPL_FS_DIR;
intern->_path_len = (int)strlen(path); intern->_path_len = strlen(path);
intern->u.dir.dirp = php_stream_opendir(path, REPORT_ERRORS, FG(default_context)); intern->u.dir.dirp = php_stream_opendir(path, REPORT_ERRORS, FG(default_context));
if (intern->_path_len > 1 && IS_SLASH_AT(path, intern->_path_len-1)) { if (intern->_path_len > 1 && IS_SLASH_AT(path, intern->_path_len-1)) {
@ -383,7 +383,7 @@ void spl_filesystem_info_set_filename(spl_filesystem_object *intern, char *path,
} }
intern->file_name = use_copy ? estrndup(path, len) : path; intern->file_name = use_copy ? estrndup(path, len) : path;
intern->file_name_len = (int)len; intern->file_name_len = len;
while (intern->file_name_len > 1 && IS_SLASH_AT(intern->file_name, intern->file_name_len-1)) { while (intern->file_name_len > 1 && IS_SLASH_AT(intern->file_name, intern->file_name_len-1)) {
intern->file_name[intern->file_name_len-1] = 0; intern->file_name[intern->file_name_len-1] = 0;
@ -397,7 +397,7 @@ void spl_filesystem_info_set_filename(spl_filesystem_object *intern, char *path,
p2 = 0; p2 = 0;
#endif #endif
if (p1 || p2) { if (p1 || p2) {
intern->_path_len = (int)((p1 > p2 ? p1 : p2) - intern->file_name); intern->_path_len = ((p1 > p2 ? p1 : p2) - intern->file_name);
} else { } else {
intern->_path_len = 0; intern->_path_len = 0;
} }
@ -408,7 +408,7 @@ void spl_filesystem_info_set_filename(spl_filesystem_object *intern, char *path,
intern->_path = estrndup(path, intern->_path_len); intern->_path = estrndup(path, intern->_path_len);
} /* }}} */ } /* }}} */
static spl_filesystem_object *spl_filesystem_object_create_info(spl_filesystem_object *source, char *file_path, int file_path_len, int use_copy, zend_class_entry *ce, zval *return_value) /* {{{ */ static spl_filesystem_object *spl_filesystem_object_create_info(spl_filesystem_object *source, char *file_path, size_t file_path_len, int use_copy, zend_class_entry *ce, zval *return_value) /* {{{ */
{ {
spl_filesystem_object *intern; spl_filesystem_object *intern;
zval arg1; zval arg1;
@ -917,7 +917,7 @@ SPL_METHOD(SplFileInfo, getExtension)
const char *p; const char *p;
size_t flen; size_t flen;
size_t path_len; size_t path_len;
int idx; size_t idx;
zend_string *ret; zend_string *ret;
if (zend_parse_parameters_none() == FAILURE) { if (zend_parse_parameters_none() == FAILURE) {
@ -938,7 +938,7 @@ SPL_METHOD(SplFileInfo, getExtension)
p = zend_memrchr(ZSTR_VAL(ret), '.', ZSTR_LEN(ret)); p = zend_memrchr(ZSTR_VAL(ret), '.', ZSTR_LEN(ret));
if (p) { if (p) {
idx = (int)(p - ZSTR_VAL(ret)); idx = p - ZSTR_VAL(ret);
RETVAL_STRINGL(ZSTR_VAL(ret) + idx + 1, ZSTR_LEN(ret) - idx - 1); RETVAL_STRINGL(ZSTR_VAL(ret) + idx + 1, ZSTR_LEN(ret) - idx - 1);
zend_string_release(ret); zend_string_release(ret);
return; return;
@ -955,7 +955,7 @@ SPL_METHOD(DirectoryIterator, getExtension)
{ {
spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis()); spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
const char *p; const char *p;
int idx; size_t idx;
zend_string *fname; zend_string *fname;
if (zend_parse_parameters_none() == FAILURE) { if (zend_parse_parameters_none() == FAILURE) {
@ -966,7 +966,7 @@ SPL_METHOD(DirectoryIterator, getExtension)
p = zend_memrchr(ZSTR_VAL(fname), '.', ZSTR_LEN(fname)); p = zend_memrchr(ZSTR_VAL(fname), '.', ZSTR_LEN(fname));
if (p) { if (p) {
idx = (int)(p - ZSTR_VAL(fname)); idx = p - ZSTR_VAL(fname);
RETVAL_STRINGL(ZSTR_VAL(fname) + idx + 1, ZSTR_LEN(fname) - idx - 1); RETVAL_STRINGL(ZSTR_VAL(fname) + idx + 1, ZSTR_LEN(fname) - idx - 1);
zend_string_release(fname); zend_string_release(fname);
} else { } else {
@ -1384,7 +1384,7 @@ SPL_METHOD(SplFileInfo, getPathInfo)
if (path) { if (path) {
char *dpath = estrndup(path, path_len); char *dpath = estrndup(path, path_len);
path_len = php_dirname(dpath, path_len); path_len = php_dirname(dpath, path_len);
spl_filesystem_object_create_info(intern, dpath, (int)path_len, 1, ce, return_value); spl_filesystem_object_create_info(intern, dpath, path_len, 1, ce, return_value);
efree(dpath); efree(dpath);
} }
} }
@ -1508,9 +1508,9 @@ SPL_METHOD(RecursiveDirectoryIterator, getChildren)
subdir = Z_SPLFILESYSTEM_P(return_value); subdir = Z_SPLFILESYSTEM_P(return_value);
if (subdir) { if (subdir) {
if (intern->u.dir.sub_path && intern->u.dir.sub_path[0]) { if (intern->u.dir.sub_path && intern->u.dir.sub_path[0]) {
subdir->u.dir.sub_path_len = (int)spprintf(&subdir->u.dir.sub_path, 0, "%s%c%s", intern->u.dir.sub_path, slash, intern->u.dir.entry.d_name); subdir->u.dir.sub_path_len = spprintf(&subdir->u.dir.sub_path, 0, "%s%c%s", intern->u.dir.sub_path, slash, intern->u.dir.entry.d_name);
} else { } else {
subdir->u.dir.sub_path_len = (int)strlen(intern->u.dir.entry.d_name); subdir->u.dir.sub_path_len = strlen(intern->u.dir.entry.d_name);
subdir->u.dir.sub_path = estrndup(intern->u.dir.entry.d_name, subdir->u.dir.sub_path_len); subdir->u.dir.sub_path = estrndup(intern->u.dir.entry.d_name, subdir->u.dir.sub_path_len);
} }
subdir->info_class = intern->info_class; subdir->info_class = intern->info_class;
@ -2294,7 +2294,7 @@ SPL_METHOD(SplFileObject, __construct)
p2 = 0; p2 = 0;
#endif #endif
if (p1 || p2) { if (p1 || p2) {
intern->_path_len = (int)((p1 > p2 ? p1 : p2) - tmp_path); intern->_path_len = ((p1 > p2 ? p1 : p2) - tmp_path);
} else { } else {
intern->_path_len = 0; intern->_path_len = 0;
} }

View file

@ -1269,11 +1269,7 @@ PHPAPI zend_string *php_escape_html_entities_ex(unsigned char *old, size_t oldle
if (oldlen < 64) { if (oldlen < 64) {
maxlen = 128; maxlen = 128;
} else { } else {
maxlen = 2 * oldlen; maxlen = zend_safe_addmult(oldlen, 2, 0, "html_entities");
if (maxlen < oldlen) {
zend_throw_error(NULL, "Input string is too long");
return NULL;
}
} }
replaced = zend_string_alloc(maxlen, 0); replaced = zend_string_alloc(maxlen, 0);

View file

@ -1140,19 +1140,15 @@ PHPAPI zend_string *_php_math_number_format_ex(double d, int dec, char *dec_poin
/* calculate the length of the return buffer */ /* calculate the length of the return buffer */
if (dp) { if (dp) {
integral = (int)(dp - ZSTR_VAL(tmpbuf)); integral = (dp - ZSTR_VAL(tmpbuf));
} else { } else {
/* no decimal point was found */ /* no decimal point was found */
integral = (int)ZSTR_LEN(tmpbuf); integral = ZSTR_LEN(tmpbuf);
} }
/* allow for thousand separators */ /* allow for thousand separators */
if (thousand_sep) { if (thousand_sep) {
if (integral + thousand_sep_len * ((integral-1) / 3) < integral) { integral = zend_safe_addmult((integral-1)/3, thousand_sep_len, integral, "number formatting");
/* overflow */
php_error_docref(NULL, E_ERROR, "String overflow");
}
integral += thousand_sep_len * ((integral-1) / 3);
} }
reslen = integral; reslen = integral;
@ -1161,11 +1157,7 @@ PHPAPI zend_string *_php_math_number_format_ex(double d, int dec, char *dec_poin
reslen += dec; reslen += dec;
if (dec_point) { if (dec_point) {
if (reslen + dec_point_len < dec_point_len) { reslen = zend_safe_addmult(reslen, 1, dec_point_len, "number formatting");
/* overflow */
php_error_docref(NULL, E_ERROR, "String overflow");
}
reslen += dec_point_len;
} }
} }
@ -1183,8 +1175,8 @@ PHPAPI zend_string *_php_math_number_format_ex(double d, int dec, char *dec_poin
* Take care, as the sprintf implementation may return less places than * Take care, as the sprintf implementation may return less places than
* we requested due to internal buffer limitations */ * we requested due to internal buffer limitations */
if (dec) { if (dec) {
int declen = (int)(dp ? s - dp : 0); size_t declen = (dp ? s - dp : 0);
int topad = dec > declen ? dec - declen : 0; size_t topad = dec > declen ? dec - declen : 0;
/* pad with '0's */ /* pad with '0's */
while (topad--) { while (topad--) {

View file

@ -268,7 +268,7 @@ static php_stream_filter *user_filter_factory_create(const char *filtername,
zval obj, zfilter; zval obj, zfilter;
zval func_name; zval func_name;
zval retval; zval retval;
int len; size_t len;
/* some sanity checks */ /* some sanity checks */
if (persistent) { if (persistent) {
@ -277,7 +277,7 @@ static php_stream_filter *user_filter_factory_create(const char *filtername,
return NULL; return NULL;
} }
len = (int)strlen(filtername); len = strlen(filtername);
/* determine the classname/class entry */ /* determine the classname/class entry */
if (NULL == (fdat = zend_hash_str_find_ptr(BG(user_filter_map), (char*)filtername, len))) { if (NULL == (fdat = zend_hash_str_find_ptr(BG(user_filter_map), (char*)filtername, len))) {
@ -289,7 +289,7 @@ static php_stream_filter *user_filter_factory_create(const char *filtername,
TODO: Allow failed userfilter creations to continue TODO: Allow failed userfilter creations to continue
scanning through the list */ scanning through the list */
if ((period = strrchr(filtername, '.'))) { if ((period = strrchr(filtername, '.'))) {
char *wildcard = emalloc(len + 3); char *wildcard = safe_emalloc(len, 1, 3);
/* Search for wildcard matches instead */ /* Search for wildcard matches instead */
memcpy(wildcard, filtername, len + 1); /* copy \0 */ memcpy(wildcard, filtername, len + 1); /* copy \0 */

View file

@ -202,7 +202,7 @@ void simplestring_addn(simplestring* target, const char* source, size_t add_len)
simplestring_init_str(target); simplestring_init_str(target);
} }
if((INT_MAX - add_len) < target->len || (INT_MAX - add_len - 1) < target->len) { 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 */ /* check for overflows, if there's a potential overflow do nothing */
return; return;
} }

View file

@ -50,8 +50,8 @@ extern "C" {
*/ */
typedef struct _simplestring { typedef struct _simplestring {
char* str; /* string buf */ char* str; /* string buf */
int len; /* length of string/buf */ size_t len; /* length of string/buf */
int size; /* size of allocated buffer */ size_t size; /* size of allocated buffer */
} simplestring; } simplestring;
/******/ /******/