summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStanislav Malyshev <stas@php.net>2016-09-12 21:09:30 -0700
committerStanislav Malyshev <stas@php.net>2016-09-12 21:09:30 -0700
commit07c6bdb85d3efe21598ebb8af6fcebceb9d486e9 (patch)
tree0fb02e7c08ec0b50791020ac862fc56e1f475135
parent2d8ab51576695630a7471ff829cc5ea10becdc0f (diff)
parentc984661d39cfa4db1dd97fde1f59c77a44991440 (diff)
downloadphp-git-07c6bdb85d3efe21598ebb8af6fcebceb9d486e9.tar.gz
Merge branch 'PHP-7.0.11' into PHP-7.0
* PHP-7.0.11: (22 commits) Fix bug #72293 - Heap overflow in mysqlnd related to BIT fields I don't think 8cceb012a7aabf3c36ab7c2724a436f976cdd165 is needed Fix test Add check in fgetcsv in case sizeof(unit) != sizeof(size_t) Fix bug #73065: Out-Of-Bounds Read in php_wddx_push_element of wddx.c Fix bug #73035 (Out of bound when verify signature of tar phar in phar_parse_tarfile) Fix bug #73052 - Memory Corruption in During Deserialized-object Destruction Fix bug #73029 - Missing type check when unserializing SplArray Fix bug #72860: wddx_deserialize use-after-free Fix bug #73007: add locale length check Fix bug #72928 - Out of bound when verify signature of zip phar in phar_parse_zipfile sync NEWS Revert "Merge branch 'PHP-5.6' into PHP-7.0" Merge branch 'PHP-5.6' into PHP-7.0 Merge branch 'PHP-5.6' into PHP-7.0 Revert "Revert "Merge branch 'PHP-5.6' into PHP-7.0"" fix version sync NEWS Fix bug #72957 set versions ...
-rw-r--r--ext/intl/msgformat/msgformat_format.c2
-rw-r--r--ext/mysqlnd/mysqlnd_wireprotocol.c7
-rw-r--r--ext/phar/tar.c2
-rw-r--r--ext/phar/tests/bug72928.phpt18
-rw-r--r--ext/phar/tests/bug72928.zipbin0 -> 140 bytes
-rw-r--r--ext/phar/tests/bug73035.phpt18
-rw-r--r--ext/phar/tests/bug73035.tarbin0 -> 10240 bytes
-rw-r--r--ext/phar/util.c28
-rw-r--r--ext/phar/zip.c2
-rw-r--r--ext/spl/spl_array.c5
-rw-r--r--ext/spl/tests/bug70068.phpt5
-rw-r--r--ext/spl/tests/bug73029.phpt16
-rw-r--r--ext/standard/tests/serialize/bug73052.phpt18
-rw-r--r--ext/standard/tests/strings/bug72703.phpt17
-rw-r--r--ext/wddx/tests/bug72860.phpt27
-rw-r--r--ext/wddx/tests/bug73065.phpt98
-rw-r--r--ext/wddx/wddx.c24
17 files changed, 255 insertions, 32 deletions
diff --git a/ext/intl/msgformat/msgformat_format.c b/ext/intl/msgformat/msgformat_format.c
index 73fb5eeff6..cb74a3fb1b 100644
--- a/ext/intl/msgformat/msgformat_format.c
+++ b/ext/intl/msgformat/msgformat_format.c
@@ -116,6 +116,8 @@ PHP_FUNCTION( msgfmt_format_message )
RETURN_FALSE;
}
+ INTL_CHECK_LOCALE_LEN(slocale_len);
+
memset(mfo, 0, sizeof(*mfo));
msgformat_data_init(&mfo->mf_data);
diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c
index 8f80bbaada..5871c3c346 100644
--- a/ext/mysqlnd/mysqlnd_wireprotocol.c
+++ b/ext/mysqlnd/mysqlnd_wireprotocol.c
@@ -1608,6 +1608,7 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
zend_uchar * p = row_buffer->ptr;
size_t data_size = row_buffer->app;
zend_uchar * bit_area = (zend_uchar*) row_buffer->ptr + data_size + 1; /* we allocate from here */
+ const zend_uchar * const packet_end = (zend_uchar*) row_buffer->ptr + data_size;
DBG_ENTER("php_mysqlnd_rowp_read_text_protocol_aux");
@@ -1619,11 +1620,15 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) {
/* php_mysqlnd_net_field_length() call should be after *this_field_len_pos = p; */
- zend_ulong len = php_mysqlnd_net_field_length(&p);
+ const zend_ulong len = php_mysqlnd_net_field_length(&p);
/* NULL or NOT NULL, this is the question! */
if (len == MYSQLND_NULL_LENGTH) {
ZVAL_NULL(current_field);
+ } else if ((p + len) > packet_end) {
+ php_error_docref(NULL, E_WARNING, "Malformed server packet. Field length pointing "MYSQLND_SZ_T_SPEC
+ " bytes after end of packet", (p + len) - packet_end - 1);
+ DBG_RETURN(FAIL);
} else {
#if defined(MYSQLND_STRING_TO_INT_CONVERSION)
struct st_mysqlnd_perm_bind perm_bind =
diff --git a/ext/phar/tar.c b/ext/phar/tar.c
index aeb5c7ef1e..72b653db97 100644
--- a/ext/phar/tar.c
+++ b/ext/phar/tar.c
@@ -286,7 +286,7 @@ bail:
}
curloc = php_stream_tell(fp);
read = php_stream_read(fp, buf, size);
- if (read != size) {
+ if (read != size || read <= 8) {
if (error) {
spprintf(error, 4096, "phar error: tar-based phar \"%s\" signature cannot be read", fname);
}
diff --git a/ext/phar/tests/bug72928.phpt b/ext/phar/tests/bug72928.phpt
new file mode 100644
index 0000000000..8e6a95418c
--- /dev/null
+++ b/ext/phar/tests/bug72928.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Phar: #72928 (Out of bound when verify signature of zip phar in phar_parse_zipfile)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+chdir(__DIR__);
+try {
+$phar = new PharData('bug72928.zip');
+var_dump($phar);
+} catch(UnexpectedValueException $e) {
+ print $e->getMessage()."\n";
+}
+?>
+DONE
+--EXPECTF--
+phar error: signature cannot be read in zip-based phar "%sbug72928.zip"
+DONE \ No newline at end of file
diff --git a/ext/phar/tests/bug72928.zip b/ext/phar/tests/bug72928.zip
new file mode 100644
index 0000000000..c480c5f537
--- /dev/null
+++ b/ext/phar/tests/bug72928.zip
Binary files differ
diff --git a/ext/phar/tests/bug73035.phpt b/ext/phar/tests/bug73035.phpt
new file mode 100644
index 0000000000..5928428abc
--- /dev/null
+++ b/ext/phar/tests/bug73035.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Phar: #73035 (Out of bound when verify signature of tar phar in phar_parse_tarfile)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+chdir(__DIR__);
+try {
+$phar = new PharData('bug73035.tar');
+var_dump($phar);
+} catch(UnexpectedValueException $e) {
+ print $e->getMessage()."\n";
+}
+?>
+DONE
+--EXPECTF--
+phar error: tar-based phar "%sbug73035.tar" signature cannot be read
+DONE \ No newline at end of file
diff --git a/ext/phar/tests/bug73035.tar b/ext/phar/tests/bug73035.tar
new file mode 100644
index 0000000000..d8e426866b
--- /dev/null
+++ b/ext/phar/tests/bug73035.tar
Binary files differ
diff --git a/ext/phar/util.c b/ext/phar/util.c
index eca33efc38..08d58b9301 100644
--- a/ext/phar/util.c
+++ b/ext/phar/util.c
@@ -1609,6 +1609,13 @@ int phar_verify_signature(php_stream *fp, size_t end_of_phar, php_uint32 sig_typ
unsigned char digest[64];
PHP_SHA512_CTX context;
+ if (sig_len < sizeof(digest)) {
+ if (error) {
+ spprintf(error, 0, "broken signature");
+ }
+ return FAILURE;
+ }
+
PHP_SHA512Init(&context);
read_len = end_of_phar;
@@ -1642,6 +1649,13 @@ int phar_verify_signature(php_stream *fp, size_t end_of_phar, php_uint32 sig_typ
unsigned char digest[32];
PHP_SHA256_CTX context;
+ if (sig_len < sizeof(digest)) {
+ if (error) {
+ spprintf(error, 0, "broken signature");
+ }
+ return FAILURE;
+ }
+
PHP_SHA256Init(&context);
read_len = end_of_phar;
@@ -1683,6 +1697,13 @@ int phar_verify_signature(php_stream *fp, size_t end_of_phar, php_uint32 sig_typ
unsigned char digest[20];
PHP_SHA1_CTX context;
+ if (sig_len < sizeof(digest)) {
+ if (error) {
+ spprintf(error, 0, "broken signature");
+ }
+ return FAILURE;
+ }
+
PHP_SHA1Init(&context);
read_len = end_of_phar;
@@ -1716,6 +1737,13 @@ int phar_verify_signature(php_stream *fp, size_t end_of_phar, php_uint32 sig_typ
unsigned char digest[16];
PHP_MD5_CTX context;
+ if (sig_len < sizeof(digest)) {
+ if (error) {
+ spprintf(error, 0, "broken signature");
+ }
+ return FAILURE;
+ }
+
PHP_MD5Init(&context);
read_len = end_of_phar;
diff --git a/ext/phar/zip.c b/ext/phar/zip.c
index 73a11870aa..a29a75d212 100644
--- a/ext/phar/zip.c
+++ b/ext/phar/zip.c
@@ -418,7 +418,7 @@ foundit:
php_stream_seek(fp, sizeof(phar_zip_file_header) + entry.header_offset + entry.filename_len + PHAR_GET_16(zipentry.extra_len), SEEK_SET);
sig = (char *) emalloc(entry.uncompressed_filesize);
read = php_stream_read(fp, sig, entry.uncompressed_filesize);
- if (read != entry.uncompressed_filesize) {
+ if (read != entry.uncompressed_filesize || read <= 8) {
php_stream_close(sigfile);
efree(sig);
PHAR_ZIP_FAIL("signature cannot be read");
diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c
index 3bb0e367ea..fe3873541e 100644
--- a/ext/spl/spl_array.c
+++ b/ext/spl/spl_array.c
@@ -295,7 +295,7 @@ static zval *spl_array_get_dimension_ptr(int check_inherited, spl_array_object *
zend_string *offset_key;
HashTable *ht = spl_array_get_hash_table(intern);
- if (!offset || Z_ISUNDEF_P(offset)) {
+ if (!offset || Z_ISUNDEF_P(offset) || !ht) {
return &EG(uninitialized_zval);
}
@@ -1790,7 +1790,8 @@ SPL_METHOD(Array, unserialize)
intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK;
zval_ptr_dtor(&intern->array);
ZVAL_UNDEF(&intern->array);
- if (!php_var_unserialize(&intern->array, &p, s + buf_len, &var_hash)) {
+ if (!php_var_unserialize(&intern->array, &p, s + buf_len, &var_hash)
+ || (Z_TYPE(intern->array) != IS_ARRAY && Z_TYPE(intern->array) != IS_OBJECT)) {
goto outexcept;
}
var_push_dtor(&var_hash, &intern->array);
diff --git a/ext/spl/tests/bug70068.phpt b/ext/spl/tests/bug70068.phpt
index 92a38dfbd6..96b2fa808f 100644
--- a/ext/spl/tests/bug70068.phpt
+++ b/ext/spl/tests/bug70068.phpt
@@ -2,8 +2,13 @@
Bug #70068 (Dangling pointer in the unserialization of ArrayObject items)
--FILE--
<?php
+try {
$a = unserialize('a:3:{i:0;C:11:"ArrayObject":20:{x:i:0;r:3;;m:a:0:{};}i:1;d:11;i:2;S:31:"AAAAAAAABBBBCCCC\01\00\00\00\04\00\00\00\00\00\00\00\00\00\00";}');
+} catch(Exception $e) {
+ print $e->getMessage()."\n";
+}
?>
OK
--EXPECT--
+Error at offset 10 of 20 bytes
OK \ No newline at end of file
diff --git a/ext/spl/tests/bug73029.phpt b/ext/spl/tests/bug73029.phpt
new file mode 100644
index 0000000000..a379f8005e
--- /dev/null
+++ b/ext/spl/tests/bug73029.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Bug #73029: Missing type check when unserializing SplArray
+--FILE--
+<?php
+try {
+$a = 'C:11:"ArrayObject":19:0x:i:0;r:2;;m:a:0:{}}';
+$m = unserialize($a);
+$x = $m[2];
+} catch(UnexpectedValueException $e) {
+ print $e->getMessage() . "\n";
+}
+?>
+DONE
+--EXPECTF--
+Error at offset 10 of 19 bytes
+DONE
diff --git a/ext/standard/tests/serialize/bug73052.phpt b/ext/standard/tests/serialize/bug73052.phpt
new file mode 100644
index 0000000000..63b484bf14
--- /dev/null
+++ b/ext/standard/tests/serialize/bug73052.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Bug #73052: Memory Corruption in During Deserialized-object Destruction
+--FILE--
+<?php
+
+class obj {
+ var $ryat;
+ public function __destruct() {
+ $this->ryat = null;
+ }
+}
+
+$poc = 'O:3:"obj":1:{';
+var_dump(unserialize($poc));
+?>
+--EXPECTF--
+Notice: unserialize(): Error at offset 13 of 13 bytes in %sbug73052.php on line %d
+bool(false)
diff --git a/ext/standard/tests/strings/bug72703.phpt b/ext/standard/tests/strings/bug72703.phpt
deleted file mode 100644
index 5e3bf4875d..0000000000
--- a/ext/standard/tests/strings/bug72703.phpt
+++ /dev/null
@@ -1,17 +0,0 @@
---TEST--
-Bug #72703 Out of bounds global memory read in BF_crypt triggered by password_verify
---SKIPIF--
-<?php
-if (!function_exists('crypt'))) {
- die("SKIP crypt() is not available");
-}
-?>
---FILE--
-<?php
- var_dump(password_verify("","$2y$10$$"));
-?>
-==OK==
---EXPECT--
-bool(false)
-==OK==
-
diff --git a/ext/wddx/tests/bug72860.phpt b/ext/wddx/tests/bug72860.phpt
new file mode 100644
index 0000000000..6385457e8e
--- /dev/null
+++ b/ext/wddx/tests/bug72860.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Bug #72860: wddx_deserialize use-after-free
+--SKIPIF--
+<?php
+if (!extension_loaded('wddx')) {
+ die('skip. wddx not available');
+}
+?>
+--FILE--
+<?php
+
+$xml=<<<XML
+<?xml version='1.0'?>
+<!DOCTYPE wddxPacket SYSTEM 'wddx_0100.dtd'>
+<wddxPacket version='1.0'>
+ <recordset fieldNames='F'>
+ <field name='F'>
+ </recordset>
+</wddxPacket>
+XML;
+
+var_dump(wddx_deserialize($xml));
+?>
+DONE
+--EXPECT--
+NULL
+DONE \ No newline at end of file
diff --git a/ext/wddx/tests/bug73065.phpt b/ext/wddx/tests/bug73065.phpt
new file mode 100644
index 0000000000..aa301aa838
--- /dev/null
+++ b/ext/wddx/tests/bug73065.phpt
@@ -0,0 +1,98 @@
+--TEST--
+Bug #73065: Out-Of-Bounds Read in php_wddx_push_element of wddx.c
+--SKIPIF--
+<?php
+if (!extension_loaded('wddx')) {
+ die('skip. wddx not available');
+}
+?>
+--FILE--
+<?php
+
+$xml1 = <<<XML
+<?xml version='1.0' ?>
+ <!DOCTYPE et SYSTEM 'w'>
+ <wddxPacket ven='1.0'>
+ <array>
+ <var Name="name">
+ <boolean value="keliu"></boolean>
+ </var>
+ <var name="1111">
+ <var name="2222">
+ <var name="3333"></var>
+ </var>
+ </var>
+ </array>
+ </wddxPacket>
+XML;
+
+$xml2 = <<<XML
+<?xml version='1.0' ?>
+ <!DOCTYPE et SYSTEM 'w'>
+ <wddxPacket ven='1.0'>
+ <array>
+ <char Name="code">
+ <boolean value="keliu"></boolean>
+ </char>
+ </array>
+ </wddxPacket>
+XML;
+
+$xml3 = <<<XML
+<?xml version='1.0' ?>
+ <!DOCTYPE et SYSTEM 'w'>
+ <wddxPacket ven='1.0'>
+ <array>
+ <boolean Name="value">
+ <boolean value="keliu"></boolean>
+ </boolean>
+ </array>
+ </wddxPacket>
+XML;
+
+$xml4 = <<<XML
+<?xml version='1.0' ?>
+ <!DOCTYPE et SYSTEM 'w'>
+ <wddxPacket ven='1.0'>
+ <array>
+ <recordset Name="fieldNames">
+ <boolean value="keliu"></boolean>
+ </recordset>
+ </array>
+ </wddxPacket>
+XML;
+
+$xml5 = <<<XML
+<?xml version='1.0' ?>
+ <!DOCTYPE et SYSTEM 'w'>
+ <wddxPacket ven='1.0'>
+ <array>
+ <field Name="name">
+ <boolean value="keliu"></boolean>
+ </field>
+ </array>
+ </wddxPacket>
+XML;
+
+for($i=1;$i<=5;$i++) {
+ $xmlvar = "xml$i";
+ $array = wddx_deserialize($$xmlvar);
+ var_dump($array);
+}
+?>
+DONE
+--EXPECTF--
+array(0) {
+}
+array(0) {
+}
+array(0) {
+}
+array(1) {
+ [0]=>
+ array(0) {
+ }
+}
+array(0) {
+}
+DONE \ No newline at end of file
diff --git a/ext/wddx/wddx.c b/ext/wddx/wddx.c
index 3a6835fbb6..7d805e484f 100644
--- a/ext/wddx/wddx.c
+++ b/ext/wddx/wddx.c
@@ -230,7 +230,10 @@ static int wddx_stack_destroy(wddx_stack *stack)
if (stack->elements) {
for (i = 0; i < stack->top; i++) {
- zval_ptr_dtor(&((st_entry *)stack->elements[i])->data);
+ if (Z_TYPE(((st_entry *)stack->elements[i])->data) != IS_UNDEF
+ && ((st_entry *)stack->elements[i])->type != ST_FIELD) {
+ zval_ptr_dtor(&((st_entry *)stack->elements[i])->data);
+ }
if (((st_entry *)stack->elements[i])->varname) {
efree(((st_entry *)stack->elements[i])->varname);
}
@@ -738,10 +741,10 @@ static void php_wddx_push_element(void *user_data, const XML_Char *name, const X
int i;
if (atts) for (i = 0; atts[i]; i++) {
- if (!strcmp((char *)atts[i], EL_CHAR_CODE) && atts[++i] && atts[i][0]) {
+ if (!strcmp((char *)atts[i], EL_CHAR_CODE) && atts[i+1] && atts[i+1][0]) {
char tmp_buf[2];
- snprintf(tmp_buf, sizeof(tmp_buf), "%c", (char)strtol((char *)atts[i], NULL, 16));
+ snprintf(tmp_buf, sizeof(tmp_buf), "%c", (char)strtol((char *)atts[i+1], NULL, 16));
php_wddx_process_data(user_data, (XML_Char *) tmp_buf, strlen(tmp_buf));
break;
}
@@ -756,13 +759,13 @@ static void php_wddx_push_element(void *user_data, const XML_Char *name, const X
int i;
if (atts) for (i = 0; atts[i]; i++) {
- if (!strcmp((char *)atts[i], EL_VALUE) && atts[++i] && atts[i][0]) {
+ if (!strcmp((char *)atts[i], EL_VALUE) && atts[i+1] && atts[i+1][0]) {
ent.type = ST_BOOLEAN;
SET_STACK_VARNAME;
ZVAL_TRUE(&ent.data);
wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
- php_wddx_process_data(user_data, atts[i], strlen((char *)atts[i]));
+ php_wddx_process_data(user_data, atts[i+1], strlen((char *)atts[i+1]));
break;
}
}
@@ -788,9 +791,9 @@ static void php_wddx_push_element(void *user_data, const XML_Char *name, const X
int i;
if (atts) for (i = 0; atts[i]; i++) {
- if (!strcmp((char *)atts[i], EL_NAME) && atts[++i] && atts[i][0]) {
+ if (!strcmp((char *)atts[i], EL_NAME) && atts[i+1] && atts[i+1][0]) {
if (stack->varname) efree(stack->varname);
- stack->varname = estrdup((char *)atts[i]);
+ stack->varname = estrdup((char *)atts[i+1]);
break;
}
}
@@ -802,11 +805,12 @@ static void php_wddx_push_element(void *user_data, const XML_Char *name, const X
array_init(&ent.data);
if (atts) for (i = 0; atts[i]; i++) {
- if (!strcmp((char *)atts[i], "fieldNames") && atts[++i] && atts[i][0]) {
+ if (!strcmp((char *)atts[i], "fieldNames") && atts[i+1] && atts[i+1][0]) {
zval tmp;
char *key;
const char *p1, *p2, *endp;
+ i++;
endp = (char *)atts[i] + strlen((char *)atts[i]);
p1 = (char *)atts[i];
while ((p2 = php_memnstr(p1, ",", sizeof(",")-1, endp)) != NULL) {
@@ -836,13 +840,13 @@ static void php_wddx_push_element(void *user_data, const XML_Char *name, const X
ZVAL_UNDEF(&ent.data);
if (atts) for (i = 0; atts[i]; i++) {
- if (!strcmp((char *)atts[i], EL_NAME) && atts[++i] && atts[i][0]) {
+ if (!strcmp((char *)atts[i], EL_NAME) && atts[i+1] && atts[i+1][0]) {
st_entry *recordset;
zval *field;
if (wddx_stack_top(stack, (void**)&recordset) == SUCCESS &&
recordset->type == ST_RECORDSET &&
- (field = zend_hash_str_find(Z_ARRVAL(recordset->data), (char*)atts[i], strlen((char *)atts[i]))) != NULL) {
+ (field = zend_hash_str_find(Z_ARRVAL(recordset->data), (char*)atts[i+1], strlen((char *)atts[i+1]))) != NULL) {
ZVAL_COPY_VALUE(&ent.data, field);
}