|
|
30ceb2 |
From 9faaee66fa493372c7340b1ab05f8fd115131a42 Mon Sep 17 00:00:00 2001
|
|
|
30ceb2 |
From: Stanislav Malyshev <stas@php.net>
|
|
|
30ceb2 |
Date: Sun, 5 Apr 2015 15:07:36 -0700
|
|
|
30ceb2 |
Subject: [PATCH] Fixed bug #69324 (Buffer Over-read in unserialize when
|
|
|
30ceb2 |
parsing Phar)
|
|
|
30ceb2 |
|
|
|
30ceb2 |
---
|
|
|
30ceb2 |
ext/phar/phar.c | 65 ++++++++++++++++++++-----------------------
|
|
|
30ceb2 |
ext/phar/phar_internal.h | 2 +-
|
|
|
30ceb2 |
ext/phar/tests/bug69324.phar | Bin 0 -> 269 bytes
|
|
|
30ceb2 |
ext/phar/tests/bug69324.phpt | 17 +++++++++++
|
|
|
30ceb2 |
4 files changed, 48 insertions(+), 36 deletions(-)
|
|
|
30ceb2 |
create mode 100644 ext/phar/tests/bug69324.phar
|
|
|
30ceb2 |
create mode 100644 ext/phar/tests/bug69324.phpt
|
|
|
30ceb2 |
|
|
|
30ceb2 |
diff --git a/ext/phar/phar.c b/ext/phar/phar.c
|
|
|
30ceb2 |
index ec82351..bf0c985 100644
|
|
|
30ceb2 |
--- a/ext/phar/phar.c
|
|
|
30ceb2 |
+++ b/ext/phar/phar.c
|
|
|
30ceb2 |
@@ -601,25 +601,18 @@ int phar_open_parsed_phar(char *fname, int fname_len, char *alias, int alias_len
|
|
|
30ceb2 |
*
|
|
|
30ceb2 |
* data is the serialized zval
|
|
|
30ceb2 |
*/
|
|
|
30ceb2 |
-int phar_parse_metadata(char **buffer, zval **metadata, int zip_metadata_len TSRMLS_DC) /* {{{ */
|
|
|
30ceb2 |
+int phar_parse_metadata(char **buffer, zval **metadata, php_uint32 zip_metadata_len TSRMLS_DC) /* {{{ */
|
|
|
30ceb2 |
{
|
|
|
30ceb2 |
const unsigned char *p;
|
|
|
30ceb2 |
- php_uint32 buf_len;
|
|
|
30ceb2 |
php_unserialize_data_t var_hash;
|
|
|
30ceb2 |
|
|
|
30ceb2 |
- if (!zip_metadata_len) {
|
|
|
30ceb2 |
- PHAR_GET_32(*buffer, buf_len);
|
|
|
30ceb2 |
- } else {
|
|
|
30ceb2 |
- buf_len = zip_metadata_len;
|
|
|
30ceb2 |
- }
|
|
|
30ceb2 |
-
|
|
|
30ceb2 |
- if (buf_len) {
|
|
|
30ceb2 |
+ if (zip_metadata_len) {
|
|
|
30ceb2 |
ALLOC_ZVAL(*metadata);
|
|
|
30ceb2 |
INIT_ZVAL(**metadata);
|
|
|
30ceb2 |
p = (const unsigned char*) *buffer;
|
|
|
30ceb2 |
PHP_VAR_UNSERIALIZE_INIT(var_hash);
|
|
|
30ceb2 |
|
|
|
30ceb2 |
- if (!php_var_unserialize(metadata, &p, p + buf_len, &var_hash TSRMLS_CC)) {
|
|
|
30ceb2 |
+ if (!php_var_unserialize(metadata, &p, p + zip_metadata_len, &var_hash TSRMLS_CC)) {
|
|
|
30ceb2 |
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
|
|
|
30ceb2 |
zval_ptr_dtor(metadata);
|
|
|
30ceb2 |
*metadata = NULL;
|
|
|
30ceb2 |
@@ -631,19 +624,14 @@ int phar_parse_metadata(char **buffer, zval **metadata, int zip_metadata_len TSR
|
|
|
30ceb2 |
if (PHAR_G(persist)) {
|
|
|
30ceb2 |
/* lazy init metadata */
|
|
|
30ceb2 |
zval_ptr_dtor(metadata);
|
|
|
30ceb2 |
- *metadata = (zval *) pemalloc(buf_len, 1);
|
|
|
30ceb2 |
- memcpy(*metadata, *buffer, buf_len);
|
|
|
30ceb2 |
- *buffer += buf_len;
|
|
|
30ceb2 |
+ *metadata = (zval *) pemalloc(zip_metadata_len, 1);
|
|
|
30ceb2 |
+ memcpy(*metadata, *buffer, zip_metadata_len);
|
|
|
30ceb2 |
return SUCCESS;
|
|
|
30ceb2 |
}
|
|
|
30ceb2 |
} else {
|
|
|
30ceb2 |
*metadata = NULL;
|
|
|
30ceb2 |
}
|
|
|
30ceb2 |
|
|
|
30ceb2 |
- if (!zip_metadata_len) {
|
|
|
30ceb2 |
- *buffer += buf_len;
|
|
|
30ceb2 |
- }
|
|
|
30ceb2 |
-
|
|
|
30ceb2 |
return SUCCESS;
|
|
|
30ceb2 |
}
|
|
|
30ceb2 |
/* }}}*/
|
|
|
30ceb2 |
@@ -664,6 +652,7 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
|
|
|
30ceb2 |
phar_entry_info entry;
|
|
|
30ceb2 |
php_uint32 manifest_len, manifest_count, manifest_flags, manifest_index, tmp_len, sig_flags;
|
|
|
30ceb2 |
php_uint16 manifest_ver;
|
|
|
30ceb2 |
+ php_uint32 len;
|
|
|
30ceb2 |
long offset;
|
|
|
30ceb2 |
int sig_len, register_alias = 0, temp_alias = 0;
|
|
|
30ceb2 |
char *signature = NULL;
|
|
|
30ceb2 |
@@ -1029,16 +1018,21 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
|
|
|
30ceb2 |
mydata->is_persistent = PHAR_G(persist);
|
|
|
30ceb2 |
|
|
|
30ceb2 |
/* check whether we have meta data, zero check works regardless of byte order */
|
|
|
30ceb2 |
+ PHAR_GET_32(buffer, len);
|
|
|
30ceb2 |
if (mydata->is_persistent) {
|
|
|
30ceb2 |
- PHAR_GET_32(buffer, mydata->metadata_len);
|
|
|
30ceb2 |
- if (phar_parse_metadata(&buffer, &mydata->metadata, mydata->metadata_len TSRMLS_CC) == FAILURE) {
|
|
|
30ceb2 |
- MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
|
|
|
30ceb2 |
- }
|
|
|
30ceb2 |
- } else {
|
|
|
30ceb2 |
- if (phar_parse_metadata(&buffer, &mydata->metadata, 0 TSRMLS_CC) == FAILURE) {
|
|
|
30ceb2 |
- MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
|
|
|
30ceb2 |
+ mydata->metadata_len = len;
|
|
|
30ceb2 |
+ if(!len) {
|
|
|
30ceb2 |
+ /* FIXME: not sure why this is needed but removing it breaks tests */
|
|
|
30ceb2 |
+ PHAR_GET_32(buffer, len);
|
|
|
30ceb2 |
}
|
|
|
30ceb2 |
}
|
|
|
30ceb2 |
+ if(len > endbuffer - buffer) {
|
|
|
30ceb2 |
+ MAPPHAR_FAIL("internal corruption of phar \"%s\" (trying to read past buffer end)");
|
|
|
30ceb2 |
+ }
|
|
|
30ceb2 |
+ if (phar_parse_metadata(&buffer, &mydata->metadata, len TSRMLS_CC) == FAILURE) {
|
|
|
30ceb2 |
+ MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
|
|
|
30ceb2 |
+ }
|
|
|
30ceb2 |
+ buffer += len;
|
|
|
30ceb2 |
|
|
|
30ceb2 |
/* set up our manifest */
|
|
|
30ceb2 |
zend_hash_init(&mydata->manifest, manifest_count,
|
|
|
30ceb2 |
@@ -1073,7 +1067,7 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
|
|
|
30ceb2 |
entry.manifest_pos = manifest_index;
|
|
|
30ceb2 |
}
|
|
|
30ceb2 |
|
|
|
30ceb2 |
- if (buffer + entry.filename_len + 20 > endbuffer) {
|
|
|
30ceb2 |
+ if (entry.filename_len + 20 > endbuffer - buffer) {
|
|
|
30ceb2 |
MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
|
|
|
30ceb2 |
}
|
|
|
30ceb2 |
|
|
|
30ceb2 |
@@ -1109,19 +1103,20 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
|
|
|
30ceb2 |
entry.flags |= PHAR_ENT_PERM_DEF_DIR;
|
|
|
30ceb2 |
}
|
|
|
30ceb2 |
|
|
|
30ceb2 |
+ PHAR_GET_32(buffer, len);
|
|
|
30ceb2 |
if (entry.is_persistent) {
|
|
|
30ceb2 |
- PHAR_GET_32(buffer, entry.metadata_len);
|
|
|
30ceb2 |
- if (!entry.metadata_len) buffer -= 4;
|
|
|
30ceb2 |
- if (phar_parse_metadata(&buffer, &entry.metadata, entry.metadata_len TSRMLS_CC) == FAILURE) {
|
|
|
30ceb2 |
- pefree(entry.filename, entry.is_persistent);
|
|
|
30ceb2 |
- MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\"");
|
|
|
30ceb2 |
- }
|
|
|
30ceb2 |
+ entry.metadata_len = len;
|
|
|
30ceb2 |
} else {
|
|
|
30ceb2 |
- if (phar_parse_metadata(&buffer, &entry.metadata, 0 TSRMLS_CC) == FAILURE) {
|
|
|
30ceb2 |
- pefree(entry.filename, entry.is_persistent);
|
|
|
30ceb2 |
- MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\"");
|
|
|
30ceb2 |
- }
|
|
|
30ceb2 |
+ entry.metadata_len = 0;
|
|
|
30ceb2 |
+ }
|
|
|
30ceb2 |
+ if (len > endbuffer - buffer) {
|
|
|
30ceb2 |
+ MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
|
|
|
30ceb2 |
+ }
|
|
|
30ceb2 |
+ if (phar_parse_metadata(&buffer, &entry.metadata, len TSRMLS_CC) == FAILURE) {
|
|
|
30ceb2 |
+ pefree(entry.filename, entry.is_persistent);
|
|
|
30ceb2 |
+ MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\"");
|
|
|
30ceb2 |
}
|
|
|
30ceb2 |
+ buffer += len;
|
|
|
30ceb2 |
|
|
|
30ceb2 |
entry.offset = entry.offset_abs = offset;
|
|
|
30ceb2 |
offset += entry.compressed_filesize;
|
|
|
30ceb2 |
diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h
|
|
|
30ceb2 |
index c9306c1..fcfc864 100644
|
|
|
30ceb2 |
--- a/ext/phar/phar_internal.h
|
|
|
30ceb2 |
+++ b/ext/phar/phar_internal.h
|
|
|
30ceb2 |
@@ -595,7 +595,7 @@ int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len,
|
|
|
30ceb2 |
char *phar_find_in_include_path(char *file, int file_len, phar_archive_data **pphar TSRMLS_DC);
|
|
|
30ceb2 |
char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC);
|
|
|
30ceb2 |
phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC);
|
|
|
30ceb2 |
-int phar_parse_metadata(char **buffer, zval **metadata, int zip_metadata_len TSRMLS_DC);
|
|
|
30ceb2 |
+int phar_parse_metadata(char **buffer, zval **metadata, php_uint32 zip_metadata_len TSRMLS_DC);
|
|
|
30ceb2 |
void destroy_phar_manifest_entry(void *pDest);
|
|
|
30ceb2 |
int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position, int follow_links TSRMLS_DC);
|
|
|
30ceb2 |
php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC);
|
|
|
30ceb2 |
--
|
|
|
30ceb2 |
2.1.4
|
|
|
30ceb2 |
|
|
|
30ceb2 |
From 12d3bdee3dfa6605024a72080d8a17c165c5ed24 Mon Sep 17 00:00:00 2001
|
|
|
30ceb2 |
From: Stanislav Malyshev <stas@php.net>
|
|
|
30ceb2 |
Date: Sat, 11 Apr 2015 16:42:16 -0700
|
|
|
30ceb2 |
Subject: [PATCH] Additional fix for bug #69324
|
|
|
30ceb2 |
|
|
|
30ceb2 |
Not so happy about duplication but needed due to bug #69429
|
|
|
30ceb2 |
---
|
|
|
30ceb2 |
ext/phar/phar.c | 13 +++++++------
|
|
|
30ceb2 |
1 file changed, 7 insertions(+), 6 deletions(-)
|
|
|
30ceb2 |
|
|
|
30ceb2 |
diff --git a/ext/phar/phar.c b/ext/phar/phar.c
|
|
|
30ceb2 |
index bf0c985..c5c8b46 100644
|
|
|
30ceb2 |
--- a/ext/phar/phar.c
|
|
|
30ceb2 |
+++ b/ext/phar/phar.c
|
|
|
30ceb2 |
@@ -598,27 +598,28 @@ int phar_open_parsed_phar(char *fname, int fname_len, char *alias, int alias_len
|
|
|
30ceb2 |
*
|
|
|
30ceb2 |
* Meta-data is in this format:
|
|
|
30ceb2 |
* [len32][data...]
|
|
|
30ceb2 |
- *
|
|
|
30ceb2 |
+ *
|
|
|
30ceb2 |
* data is the serialized zval
|
|
|
30ceb2 |
*/
|
|
|
30ceb2 |
int phar_parse_metadata(char **buffer, zval **metadata, php_uint32 zip_metadata_len TSRMLS_DC) /* {{{ */
|
|
|
30ceb2 |
{
|
|
|
30ceb2 |
- const unsigned char *p;
|
|
|
30ceb2 |
php_unserialize_data_t var_hash;
|
|
|
30ceb2 |
|
|
|
30ceb2 |
if (zip_metadata_len) {
|
|
|
30ceb2 |
+ const unsigned char *p, *p_buff = estrndup(*buffer, zip_metadata_len);
|
|
|
30ceb2 |
+ p = p_buff;
|
|
|
30ceb2 |
ALLOC_ZVAL(*metadata);
|
|
|
30ceb2 |
INIT_ZVAL(**metadata);
|
|
|
30ceb2 |
- p = (const unsigned char*) *buffer;
|
|
|
30ceb2 |
PHP_VAR_UNSERIALIZE_INIT(var_hash);
|
|
|
30ceb2 |
|
|
|
30ceb2 |
if (!php_var_unserialize(metadata, &p, p + zip_metadata_len, &var_hash TSRMLS_CC)) {
|
|
|
30ceb2 |
+ efree(p_buff);
|
|
|
30ceb2 |
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
|
|
|
30ceb2 |
zval_ptr_dtor(metadata);
|
|
|
30ceb2 |
*metadata = NULL;
|
|
|
30ceb2 |
return FAILURE;
|
|
|
30ceb2 |
}
|
|
|
30ceb2 |
-
|
|
|
30ceb2 |
+ efree(p_buff);
|
|
|
30ceb2 |
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
|
|
|
30ceb2 |
|
|
|
30ceb2 |
if (PHAR_G(persist)) {
|
|
|
30ceb2 |
@@ -641,7 +642,7 @@ int phar_parse_metadata(char **buffer, zval **metadata, php_uint32 zip_metadata_
|
|
|
30ceb2 |
*
|
|
|
30ceb2 |
* Parse a new one and add it to the cache, returning either SUCCESS or
|
|
|
30ceb2 |
* FAILURE, and setting pphar to the pointer to the manifest entry
|
|
|
30ceb2 |
- *
|
|
|
30ceb2 |
+ *
|
|
|
30ceb2 |
* This is used by phar_open_from_filename to process the manifest, but can be called
|
|
|
30ceb2 |
* directly.
|
|
|
30ceb2 |
*/
|
|
|
30ceb2 |
@@ -2234,7 +2235,7 @@ last_time:
|
|
|
30ceb2 |
|
|
|
30ceb2 |
/**
|
|
|
30ceb2 |
* Process a phar stream name, ensuring we can handle any of:
|
|
|
30ceb2 |
- *
|
|
|
30ceb2 |
+ *
|
|
|
30ceb2 |
* - whatever.phar
|
|
|
30ceb2 |
* - whatever.phar.gz
|
|
|
30ceb2 |
* - whatever.phar.bz2
|
|
|
30ceb2 |
--
|
|
|
30ceb2 |
2.1.4
|
|
|
30ceb2 |
|
|
|
30ceb2 |
From cee97220285fd7b955a58617b3e0300ec104ed87 Mon Sep 17 00:00:00 2001
|
|
|
30ceb2 |
From: Dmitry Stogov <dmitry@zend.com>
|
|
|
30ceb2 |
Date: Tue, 14 Apr 2015 15:47:26 +0300
|
|
|
30ceb2 |
Subject: [PATCH] Fixed recently introduced memory leak
|
|
|
30ceb2 |
|
|
|
30ceb2 |
---
|
|
|
30ceb2 |
ext/phar/phar.c | 1 +
|
|
|
30ceb2 |
1 file changed, 1 insertion(+)
|
|
|
30ceb2 |
|
|
|
30ceb2 |
diff --git a/ext/phar/phar.c b/ext/phar/phar.c
|
|
|
30ceb2 |
index c5c8b46..223bfe8 100644
|
|
|
30ceb2 |
--- a/ext/phar/phar.c
|
|
|
30ceb2 |
+++ b/ext/phar/phar.c
|
|
|
30ceb2 |
@@ -1113,6 +1113,7 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
|
|
|
30ceb2 |
entry.metadata_len = 0;
|
|
|
30ceb2 |
}
|
|
|
30ceb2 |
if (len > endbuffer - buffer) {
|
|
|
30ceb2 |
+ pefree(entry.filename, entry.is_persistent);
|
|
|
30ceb2 |
MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
|
|
|
30ceb2 |
}
|
|
|
30ceb2 |
if (phar_parse_metadata(&buffer, &entry.metadata, len TSRMLS_CC) == FAILURE) {
|
|
|
30ceb2 |
--
|
|
|
30ceb2 |
2.1.4
|
|
|
30ceb2 |
|