Skip to content

Instantly share code, notes, and snippets.

/overflow.diff Secret
Created Sep 2, 2016

Embed
What would you like to do?
Patch for overflow
commit 0f1eb74e92191e817b4198ceda4e8f093699da62
Author: Stanislav Malyshev <stas@php.net>
Date: Thu Sep 1 23:15:34 2016 -0700
Fix various int size overflows.
Add function for detection of string zvals with length that does not fit
INT_MAX.
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index 7e622c6..1f50016 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -1279,9 +1279,14 @@ ZEND_API int add_assoc_double_ex(zval *arg, const char *key, uint key_len, doubl
ZEND_API int add_assoc_string_ex(zval *arg, const char *key, uint key_len, char *str, int duplicate) /* {{{ */
{
zval *tmp;
+ size_t _len = strlen(str);
+
+ if (UNEXPECTED(_len > INT_MAX)) {
+ zend_error_noreturn(E_ERROR, "String overflow, max size is %d", INT_MAX);
+ }
MAKE_STD_ZVAL(tmp);
- ZVAL_STRING(tmp, str, duplicate);
+ ZVAL_STRINGL(tmp, str, _len, duplicate);
return zend_symtable_update(Z_ARRVAL_P(arg), key, key_len, (void *) &tmp, sizeof(zval *), NULL);
}
@@ -1291,6 +1296,10 @@ ZEND_API int add_assoc_stringl_ex(zval *arg, const char *key, uint key_len, char
{
zval *tmp;
+ if (UNEXPECTED(length > INT_MAX)) {
+ zend_error_noreturn(E_ERROR, "String overflow, max size is %d", INT_MAX);
+ }
+
MAKE_STD_ZVAL(tmp);
ZVAL_STRINGL(tmp, str, length, duplicate);
@@ -1362,6 +1371,11 @@ ZEND_API int add_index_double(zval *arg, ulong index, double d) /* {{{ */
ZEND_API int add_index_string(zval *arg, ulong index, const char *str, int duplicate) /* {{{ */
{
zval *tmp;
+ size_t _len = strlen(str);
+
+ if (UNEXPECTED(_len > INT_MAX)) {
+ zend_error_noreturn(E_ERROR, "String overflow, max size is %d", INT_MAX);
+ }
MAKE_STD_ZVAL(tmp);
ZVAL_STRING(tmp, str, duplicate);
@@ -1374,6 +1388,10 @@ ZEND_API int add_index_stringl(zval *arg, ulong index, const char *str, uint len
{
zval *tmp;
+ if (UNEXPECTED(length > INT_MAX)) {
+ zend_error_noreturn(E_ERROR, "String overflow, max size is %d", INT_MAX);
+ }
+
MAKE_STD_ZVAL(tmp);
ZVAL_STRINGL(tmp, str, length, duplicate);
@@ -1457,6 +1475,9 @@ ZEND_API int add_next_index_stringl(zval *arg, const char *str, uint length, int
{
zval *tmp;
+ if (UNEXPECTED(length > INT_MAX)) {
+ zend_error_noreturn(E_ERROR, "String overflow, max size is %d", INT_MAX);
+ }
MAKE_STD_ZVAL(tmp);
ZVAL_STRINGL(tmp, str, length, duplicate);
@@ -1473,9 +1494,14 @@ ZEND_API int add_next_index_zval(zval *arg, zval *value) /* {{{ */
ZEND_API int add_get_assoc_string_ex(zval *arg, const char *key, uint key_len, const char *str, void **dest, int duplicate) /* {{{ */
{
zval *tmp;
+ size_t _len = strlen(str);
+
+ if (UNEXPECTED(_len > INT_MAX)) {
+ zend_error_noreturn(E_ERROR, "String overflow, max size is %d", INT_MAX);
+ }
MAKE_STD_ZVAL(tmp);
- ZVAL_STRING(tmp, str, duplicate);
+ ZVAL_STRINGL(tmp, str, _len, duplicate);
return zend_symtable_update(Z_ARRVAL_P(arg), key, key_len, (void *) &tmp, sizeof(zval *), dest);
}
@@ -1485,6 +1511,10 @@ ZEND_API int add_get_assoc_stringl_ex(zval *arg, const char *key, uint key_len,
{
zval *tmp;
+ if (UNEXPECTED(length > INT_MAX)) {
+ zend_error_noreturn(E_ERROR, "String overflow, max size is %d", INT_MAX);
+ }
+
MAKE_STD_ZVAL(tmp);
ZVAL_STRINGL(tmp, str, length, duplicate);
@@ -1664,9 +1694,14 @@ ZEND_API int add_property_string_ex(zval *arg, const char *key, uint key_len, co
{
zval *tmp;
zval *z_key;
+ size_t _len = strlen(str);
+
+ if (UNEXPECTED(_len > INT_MAX)) {
+ zend_error_noreturn(E_ERROR, "String overflow, max size is %d", INT_MAX);
+ }
MAKE_STD_ZVAL(tmp);
- ZVAL_STRING(tmp, str, duplicate);
+ ZVAL_STRINGL(tmp, str, _len, duplicate);
MAKE_STD_ZVAL(z_key);
ZVAL_STRINGL(z_key, key, key_len-1, 1);
@@ -1683,6 +1718,10 @@ ZEND_API int add_property_stringl_ex(zval *arg, const char *key, uint key_len, c
zval *tmp;
zval *z_key;
+ if (UNEXPECTED(length > INT_MAX)) {
+ zend_error_noreturn(E_ERROR, "String overflow, max size is %d", INT_MAX);
+ }
+
MAKE_STD_ZVAL(tmp);
ZVAL_STRINGL(tmp, str, length, duplicate);
diff --git a/Zend/zend_API.h b/Zend/zend_API.h
index e17be4c..3e191b6 100644
--- a/Zend/zend_API.h
+++ b/Zend/zend_API.h
@@ -654,6 +654,20 @@ END_EXTERN_C()
} while (0)
#define RETURN_ZVAL_FAST(z) { RETVAL_ZVAL_FAST(z); return; }
+/* Check that returned string length fits int */
+#define RETVAL_STRINGL_CHECK(s, len, dup) \
+ size_t __len = (len); \
+ if (UNEXPECTED(__len > INT_MAX)) { \
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "String too long, max is %d", INT_MAX); \
+ if(!(dup)) { \
+ efree((s)); \
+ } \
+ RETURN_FALSE; \
+ } \
+ RETVAL_STRINGL((s), __len, (dup))
+
+
+
#define SET_VAR_STRING(n, v) { \
{ \
zval *var; \
diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c
index 105c256..1f00414 100644
--- a/Zend/zend_alloc.c
+++ b/Zend/zend_alloc.c
@@ -2578,6 +2578,15 @@ static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
#endif
+ZEND_API void *_safe_emalloc_string(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
+{
+ size_t str_size = safe_address(nmemb, size, offset);
+ if (UNEXPECTED(str_size > INT_MAX)) {
+ zend_error_noreturn(E_ERROR, "String allocation overflow, max size is %d", INT_MAX);
+ }
+ return emalloc_rel(str_size);
+}
+
ZEND_API void *_safe_emalloc(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
{
return emalloc_rel(safe_address(nmemb, size, offset));
diff --git a/Zend/zend_alloc.h b/Zend/zend_alloc.h
index 8169364..719f9c5 100644
--- a/Zend/zend_alloc.h
+++ b/Zend/zend_alloc.h
@@ -56,6 +56,7 @@ ZEND_API char *zend_strndup(const char *s, unsigned int length) ZEND_ATTRIBUTE_M
ZEND_API void *_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_MALLOC ZEND_ATTRIBUTE_ALLOC_SIZE(1);
ZEND_API void *_safe_emalloc(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_MALLOC;
+ZEND_API void *_safe_emalloc_string(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_MALLOC;
ZEND_API void *_safe_malloc(size_t nmemb, size_t size, size_t offset) ZEND_ATTRIBUTE_MALLOC;
ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
ZEND_API void *_ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_MALLOC ZEND_ATTRIBUTE_ALLOC_SIZE2(1,2);
@@ -69,6 +70,7 @@ ZEND_API size_t _zend_mem_block_size(void *ptr TSRMLS_DC ZEND_FILE_LINE_DC ZEND_
/* Standard wrapper macros */
#define emalloc(size) _emalloc((size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define safe_emalloc(nmemb, size, offset) _safe_emalloc((nmemb), (size), (offset) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
+#define safe_emalloc_string(nmemb, size, offset) _safe_emalloc_string((nmemb), (size), (offset) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define efree(ptr) _efree((ptr) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define ecalloc(nmemb, size) _ecalloc((nmemb), (size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define erealloc(ptr, size) _erealloc((ptr), (size), 0 ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
diff --git a/ext/imap/php_imap.c b/ext/imap/php_imap.c
index d5d3e22..8fe9de9 100644
--- a/ext/imap/php_imap.c
+++ b/ext/imap/php_imap.c
@@ -1711,7 +1711,7 @@ PHP_FUNCTION(imap_body)
if (body_len == 0) {
RETVAL_EMPTY_STRING();
} else {
- RETVAL_STRINGL(body, body_len, 1);
+ RETVAL_STRINGL_CHECK(body, body_len, 1);
}
}
/* }}} */
@@ -1899,7 +1899,7 @@ PHP_FUNCTION(imap_list_full)
}
array_init(return_value);
- delim = safe_emalloc(2, sizeof(char), 0);
+ delim = emalloc(2);
cur=IMAPG(imap_folder_objects);
while (cur != NIL) {
MAKE_STD_ZVAL(mboxob);
@@ -2205,7 +2205,7 @@ PHP_FUNCTION(imap_lsub_full)
}
array_init(return_value);
- delim = safe_emalloc(2, sizeof(char), 0);
+ delim = emalloc(2);
cur=IMAPG(imap_sfolder_objects);
while (cur != NIL) {
MAKE_STD_ZVAL(mboxob);
@@ -2356,7 +2356,7 @@ PHP_FUNCTION(imap_fetchbody)
php_error_docref(NULL TSRMLS_CC, E_WARNING, "No body information available");
RETURN_FALSE;
}
- RETVAL_STRINGL(body, len, 1);
+ RETVAL_STRINGL_CHECK(body, len, 1);
}
/* }}} */
@@ -2396,7 +2396,12 @@ PHP_FUNCTION(imap_fetchmime)
php_error_docref(NULL TSRMLS_CC, E_WARNING, "No body MIME information available");
RETURN_FALSE;
}
- RETVAL_STRINGL(body, len, 1);
+ if (len > INT_MAX) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "String too long, max is %d", INT_MAX);
+ efree(body);
+ RETURN_FALSE;
+ }
+ RETVAL_STRINGL_CHECK(body, len, 1);
}
/* }}} */
@@ -2495,7 +2500,7 @@ PHP_FUNCTION(imap_qprint)
RETURN_FALSE;
}
- RETVAL_STRINGL(decode, newlength, 1);
+ RETVAL_STRINGL_CHECK(decode, newlength, 1);
fs_give((void**) &decode);
}
/* }}} */
@@ -2541,7 +2546,7 @@ PHP_FUNCTION(imap_binary)
RETURN_FALSE;
}
- RETVAL_STRINGL(decode, newlength, 1);
+ RETVAL_STRINGL_CHECK(decode, newlength, 1);
fs_give((void**) &decode);
}
/* }}} */
@@ -2626,7 +2631,7 @@ PHP_FUNCTION(imap_rfc822_write_address)
string = _php_rfc822_write_address(addr TSRMLS_CC);
if (string) {
- RETVAL_STRING(string, 0);
+ RETVAL_STRINGL_CHECK(string, strlen(string), 0);
} else {
RETURN_FALSE;
}
@@ -2882,7 +2887,8 @@ PHP_FUNCTION(imap_utf7_encode)
const unsigned char *in, *inp, *endp;
unsigned char *out, *outp;
unsigned char c;
- int arg_len, inlen, outlen;
+ int arg_len, inlen;
+ size_t outlen;
enum {
ST_NORMAL, /* printable text */
ST_ENCODE0, /* encoded text rotation... */
@@ -2929,7 +2935,7 @@ PHP_FUNCTION(imap_utf7_encode)
}
/* allocate output buffer */
- out = emalloc(outlen + 1);
+ out = safe_emalloc_string(1, outlen, 1);
/* encode input string */
outp = out;
@@ -3019,7 +3025,7 @@ static void php_imap_mutf7(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
if (out == NIL) {
RETURN_FALSE;
} else {
- RETURN_STRING((char *)out, 1);
+ RETVAL_STRINGL_CHECK((char *)out, strlen(out), 1);
}
}
/* }}} */
diff --git a/ext/ldap/ldap.c b/ext/ldap/ldap.c
index e709e59..8ab0fe0 100644
--- a/ext/ldap/ldap.c
+++ b/ext/ldap/ldap.c
@@ -2647,7 +2647,7 @@ static void php_ldap_do_escape(const zend_bool *map, const char *value, size_t v
len += (map[(unsigned char) value[i]]) ? 3 : 1;
}
- (*result) = (char *) safe_emalloc(1, len, 1);
+ (*result) = (char *) safe_emalloc_string(1, len, 1);
(*resultlen) = len;
for (i = 0; i < valuelen; i++) {
diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c
index ddc5d76..b5d9ca3 100644
--- a/ext/pcre/php_pcre.c
+++ b/ext/pcre/php_pcre.c
@@ -1761,7 +1761,7 @@ static PHP_FUNCTION(preg_quote)
/* Allocate enough memory so that even if each character
is quoted, we won't run out of room */
- out_str = safe_emalloc(4, in_str_len, 1);
+ out_str = safe_emalloc_string(4, in_str_len, 1);
/* Go through the string and quote necessary characters */
for(p = in_str, q = out_str; p != in_str_end; p++) {
diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c
index 8f3518d..a1835bf 100644
--- a/ext/pgsql/pgsql.c
+++ b/ext/pgsql/pgsql.c
@@ -4325,7 +4325,7 @@ PHP_FUNCTION(pg_escape_string)
break;
}
- to = (char *) safe_emalloc(from_len, 2, 1);
+ to = (char *) safe_emalloc_string(from_len, 2, 1);
#ifdef HAVE_PQESCAPE_CONN
if (pgsql_link != NULL || id != -1) {
ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
@@ -4374,7 +4374,7 @@ PHP_FUNCTION(pg_escape_bytea)
#endif
to = (char *)PQescapeBytea((unsigned char*)from, from_len, &to_len);
- RETVAL_STRINGL(to, to_len-1, 1); /* to_len includes additional '\0' */
+ RETVAL_STRINGL_CHECK(to, to_len-1, 1); /* to_len includes additional '\0' */
PQfreemem(to);
}
/* }}} */
@@ -4561,7 +4561,7 @@ static void php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAMETERS, int escape_l
to = estrdup(tmp);
PGSQLfree(tmp);
- RETURN_STRING(to, 0);
+ RETVAL_STRINGL_CHECK(to, strlen(to), 0);
}
/* {{{ proto string pg_escape_literal([resource connection,] string data)
diff --git a/ext/standard/string.c b/ext/standard/string.c
index 9498496..da473d9 100644
--- a/ext/standard/string.c
+++ b/ext/standard/string.c
@@ -2401,7 +2401,7 @@ PHP_FUNCTION(substr_replace)
l = Z_STRLEN_PP(str);
}
- if ((f + l) > Z_STRLEN_PP(str)) {
+ if (f > Z_STRLEN_PP(str) - l) {
l = Z_STRLEN_PP(str) - f;
}
if (Z_TYPE_PP(repl) == IS_ARRAY) {
@@ -2414,7 +2414,7 @@ PHP_FUNCTION(substr_replace)
repl_len = Z_STRLEN_PP(repl);
}
result_len = Z_STRLEN_PP(str) - l + repl_len;
- result = emalloc(result_len + 1);
+ result = safe_emalloc_string(1, result_len, 1);
memcpy(result, Z_STRVAL_PP(str), f);
if (repl_len) {
@@ -2556,7 +2556,7 @@ PHP_FUNCTION(substr_replace)
result_len += Z_STRLEN_P(repl_str);
zend_hash_move_forward_ex(Z_ARRVAL_PP(repl), &pos_repl);
- result = emalloc(result_len + 1);
+ result = safe_emalloc_string(1, result_len, 1);
memcpy(result, Z_STRVAL_P(orig_str), f);
memcpy((result + f), Z_STRVAL_P(repl_str), Z_STRLEN_P(repl_str));
@@ -2565,7 +2565,7 @@ PHP_FUNCTION(substr_replace)
zval_dtor(repl_str);
}
} else {
- result = emalloc(result_len + 1);
+ result = safe_emalloc_string(1, result_len, 1);
memcpy(result, Z_STRVAL_P(orig_str), f);
memcpy((result + f), Z_STRVAL_P(orig_str) + f + l, Z_STRLEN_P(orig_str) - f - l);
@@ -2573,7 +2573,7 @@ PHP_FUNCTION(substr_replace)
} else {
result_len += Z_STRLEN_PP(repl);
- result = emalloc(result_len + 1);
+ result = safe_emalloc_string(1, result_len, 1);
memcpy(result, Z_STRVAL_P(orig_str), f);
memcpy((result + f), Z_STRVAL_PP(repl), Z_STRLEN_PP(repl));
@@ -2620,7 +2620,7 @@ PHP_FUNCTION(quotemeta)
RETURN_FALSE;
}
- str = safe_emalloc(2, old_len, 1);
+ str = safe_emalloc_string(2, old_len, 1);
for (p = old, q = str; p != old_end; p++) {
c = *p;
@@ -3646,7 +3646,7 @@ PHPAPI int php_char_to_str_ex(char *str, uint len, char from, char *to, int to_l
if (Z_STRLEN_P(result) < 0) {
zend_error(E_ERROR, "String size overflow");
}
- Z_STRVAL_P(result) = target = safe_emalloc(char_count, to_len, len + 1);
+ Z_STRVAL_P(result) = target = safe_emalloc_string(char_count, to_len, len + 1);
Z_TYPE_P(result) = IS_STRING;
if (case_sensitivity) {
@@ -3776,7 +3776,7 @@ PHPAPI char *php_str_to_str_ex(char *haystack, int length,
}
return new_str;
} else {
- new_str = safe_emalloc(count, str_len - needle_len, length + 1);
+ new_str = safe_emalloc_string(count, str_len - needle_len, length + 1);
}
}
@@ -4307,10 +4307,7 @@ PHP_FUNCTION(nl2br)
size_t repl_len = is_xhtml ? (sizeof("<br />") - 1) : (sizeof("<br>") - 1);
new_length = str_len + repl_cnt * repl_len;
- if (UNEXPECTED(new_length > INT_MAX)) {
- zend_error(E_ERROR, "String size overflow");
- }
- tmp = target = safe_emalloc(repl_cnt, repl_len, str_len + 1);
+ tmp = target = safe_emalloc_string(repl_cnt, repl_len, str_len + 1);
}
while (str < end) {
@@ -5303,7 +5300,7 @@ PHP_FUNCTION(str_pad)
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Padding length is too long");
return;
}
- result = (char *)emalloc(input_len + num_pad_chars + 1);
+ result = (char *)safe_emalloc_string(1, input_len, num_pad_chars + 1);
/* We need to figure out the left/right padding lengths. */
switch (pad_type_val) {
diff --git a/ext/xml/xml.c b/ext/xml/xml.c
index 5912f91..96a76ef 100644
--- a/ext/xml/xml.c
+++ b/ext/xml/xml.c
@@ -12,7 +12,7 @@
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
- | Authors: Stig Sæther Bakken <ssb@php.net> |
+ | Authors: Stig Sæther Bakken <ssb@php.net> |
| Thies C. Arntzen <thies@thieso.net> |
| Sterling Hughes <sterling@php.net> |
+----------------------------------------------------------------------+
@@ -638,7 +638,7 @@ PHPAPI char *xml_utf8_encode(const char *s, int len, int *newlen, const XML_Char
}
/* This is the theoretical max (will never get beyond len * 2 as long
* as we are converting from single-byte characters, though) */
- newbuf = safe_emalloc(len, 4, 1);
+ newbuf = safe_emalloc_string(len, 4, 1);
while (pos > 0) {
c = encoder ? encoder((unsigned char)(*s)) : (unsigned short)(*s);
if (c < 0x80) {
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index ea0d502..e33b2cc 100644
--- a/ext/zlib/zlib.c
+++ b/ext/zlib/zlib.c
@@ -693,7 +693,7 @@ static PHP_FUNCTION(name) \
if (SUCCESS != php_zlib_decode(in_buf, in_len, &out_buf, &out_len, encoding, max_len TSRMLS_CC)) { \
RETURN_FALSE; \
} \
- RETURN_STRINGL(out_buf, out_len, 0); \
+ RETVAL_STRINGL_CHECK(out_buf, out_len, 0); \
}
/* {{{ proto binary zlib_encode(binary data, int encoding[, int level = -1])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.