components/php-5_3/php-sapi/patches/261_php_20936509.patch
changeset 4494 f5b717124172
equal deleted inserted replaced
4490:5a5296580120 4494:f5b717124172
       
     1 CVE-2015-2783
       
     2 Community BUG:
       
     3 https://bugs.php.net/bug.php?id=69324
       
     4 Community CODE:
       
     5 http://git.php.net/?p=php-src.git;a=commit;h=9faaee66fa493372c7340b1ab05f8fd115131a42
       
     6 Below is the community patch.
       
     7 
       
     8 Not including the test files at the moment:
       
     9 ext/phar/tests/bug69324.phar
       
    10 ext/phar/tests/bug69324.phpt
       
    11 because our version of gpatch doesn't understand the git binary data file.
       
    12 
       
    13 
       
    14 
       
    15 From 9faaee66fa493372c7340b1ab05f8fd115131a42 Mon Sep 17 00:00:00 2001
       
    16 From: Stanislav Malyshev <[email protected]>
       
    17 Date: Sun, 5 Apr 2015 15:07:36 -0700
       
    18 Subject: [PATCH] Fixed bug #69324 (Buffer Over-read in unserialize when
       
    19  parsing Phar)
       
    20 
       
    21 ---
       
    22  ext/phar/phar.c              |  65 ++++++++++++++++++++-----------------------
       
    23  ext/phar/phar_internal.h     |   2 +-
       
    24  ext/phar/tests/bug69324.phar | Bin 0 -> 269 bytes
       
    25  ext/phar/tests/bug69324.phpt |  17 +++++++++++
       
    26  4 files changed, 48 insertions(+), 36 deletions(-)
       
    27  create mode 100644 ext/phar/tests/bug69324.phar
       
    28  create mode 100644 ext/phar/tests/bug69324.phpt
       
    29 
       
    30 diff --git a/ext/phar/phar.c b/ext/phar/phar.c
       
    31 index ec82351..bf0c985 100644
       
    32 --- a/ext/phar/phar.c
       
    33 +++ b/ext/phar/phar.c
       
    34 @@ -603,25 +603,18 @@ int phar_open_parsed_phar(char *fname, int fname_len, char *alias, int alias_len
       
    35   * 
       
    36   * data is the serialized zval
       
    37   */
       
    38 -int phar_parse_metadata(char **buffer, zval **metadata, int zip_metadata_len TSRMLS_DC) /* {{{ */
       
    39 +int phar_parse_metadata(char **buffer, zval **metadata, php_uint32 zip_metadata_len TSRMLS_DC) /* {{{ */
       
    40  {
       
    41  	const unsigned char *p;
       
    42 -	php_uint32 buf_len;
       
    43  	php_unserialize_data_t var_hash;
       
    44  
       
    45 -	if (!zip_metadata_len) {
       
    46 -		PHAR_GET_32(*buffer, buf_len);
       
    47 -	} else {
       
    48 -		buf_len = zip_metadata_len;
       
    49 -	}
       
    50 -
       
    51 -	if (buf_len) {
       
    52 +	if (zip_metadata_len) {
       
    53  		ALLOC_ZVAL(*metadata);
       
    54  		INIT_ZVAL(**metadata);
       
    55  		p = (const unsigned char*) *buffer;
       
    56  		PHP_VAR_UNSERIALIZE_INIT(var_hash);
       
    57  
       
    58 -		if (!php_var_unserialize(metadata, &p, p + buf_len, &var_hash TSRMLS_CC)) {
       
    59 +		if (!php_var_unserialize(metadata, &p, p + zip_metadata_len, &var_hash TSRMLS_CC)) {
       
    60  			PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
       
    61  			zval_ptr_dtor(metadata);
       
    62  			*metadata = NULL;
       
    63 @@ -633,19 +626,14 @@ int phar_parse_metadata(char **buffer, zval **metadata, int zip_metadata_len TSR
       
    64  		if (PHAR_G(persist)) {
       
    65  			/* lazy init metadata */
       
    66  			zval_ptr_dtor(metadata);
       
    67 -			*metadata = (zval *) pemalloc(buf_len, 1);
       
    68 -			memcpy(*metadata, *buffer, buf_len);
       
    69 -			*buffer += buf_len;
       
    70 +			*metadata = (zval *) pemalloc(zip_metadata_len, 1);
       
    71 +			memcpy(*metadata, *buffer, zip_metadata_len);
       
    72  			return SUCCESS;
       
    73  		}
       
    74  	} else {
       
    75  		*metadata = NULL;
       
    76  	}
       
    77  
       
    78 -	if (!zip_metadata_len) {
       
    79 -		*buffer += buf_len;
       
    80 -	}
       
    81 -
       
    82  	return SUCCESS;
       
    83  }
       
    84  /* }}}*/
       
    85 @@ -666,6 +654,7 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
       
    86  	phar_entry_info entry;
       
    87  	php_uint32 manifest_len, manifest_count, manifest_flags, manifest_index, tmp_len, sig_flags;
       
    88  	php_uint16 manifest_ver;
       
    89 +	php_uint32 len;
       
    90  	long offset;
       
    91  	int sig_len, register_alias = 0, temp_alias = 0;
       
    92  	char *signature = NULL;
       
    93 @@ -1031,16 +1020,21 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
       
    94  	mydata->is_persistent = PHAR_G(persist);
       
    95  
       
    96  	/* check whether we have meta data, zero check works regardless of byte order */
       
    97 +	PHAR_GET_32(buffer, len);
       
    98  	if (mydata->is_persistent) {
       
    99 -		PHAR_GET_32(buffer, mydata->metadata_len);
       
   100 -		if (phar_parse_metadata(&buffer, &mydata->metadata, mydata->metadata_len TSRMLS_CC) == FAILURE) {
       
   101 -			MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
       
   102 -		}
       
   103 -	} else {
       
   104 -		if (phar_parse_metadata(&buffer, &mydata->metadata, 0 TSRMLS_CC) == FAILURE) {
       
   105 -			MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
       
   106 +		mydata->metadata_len = len;
       
   107 +		if(!len) {
       
   108 +			/* FIXME: not sure why this is needed but removing it breaks tests */
       
   109 +			PHAR_GET_32(buffer, len);
       
   110  		}
       
   111  	}
       
   112 +	if(len > endbuffer - buffer) {
       
   113 +		MAPPHAR_FAIL("internal corruption of phar \"%s\" (trying to read past buffer end)");
       
   114 +	}
       
   115 +	if (phar_parse_metadata(&buffer, &mydata->metadata, len TSRMLS_CC) == FAILURE) {
       
   116 +		MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
       
   117 +	}
       
   118 +	buffer += len;
       
   119  
       
   120  	/* set up our manifest */
       
   121  	zend_hash_init(&mydata->manifest, manifest_count,
       
   122 @@ -1075,7 +1069,7 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
       
   123  			entry.manifest_pos = manifest_index;
       
   124  		}
       
   125  
       
   126 -		if (buffer + entry.filename_len + 20 > endbuffer) {
       
   127 +		if (entry.filename_len + 20 > endbuffer - buffer) {
       
   128  			MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
       
   129  		}
       
   130  
       
   131 @@ -1111,19 +1105,20 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
       
   132  			entry.flags |= PHAR_ENT_PERM_DEF_DIR;
       
   133  		}
       
   134  
       
   135 +		PHAR_GET_32(buffer, len);
       
   136  		if (entry.is_persistent) {
       
   137 -			PHAR_GET_32(buffer, entry.metadata_len);
       
   138 -			if (!entry.metadata_len) buffer -= 4;
       
   139 -			if (phar_parse_metadata(&buffer, &entry.metadata, entry.metadata_len TSRMLS_CC) == FAILURE) {
       
   140 -				pefree(entry.filename, entry.is_persistent);
       
   141 -				MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\"");
       
   142 -			}
       
   143 +			entry.metadata_len = len;
       
   144  		} else {
       
   145 -			if (phar_parse_metadata(&buffer, &entry.metadata, 0 TSRMLS_CC) == FAILURE) {
       
   146 -				pefree(entry.filename, entry.is_persistent);
       
   147 -				MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\"");
       
   148 -			}
       
   149 +			entry.metadata_len = 0;
       
   150 +		}
       
   151 +		if (len > endbuffer - buffer) {
       
   152 +			MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
       
   153 +		}
       
   154 +		if (phar_parse_metadata(&buffer, &entry.metadata, len TSRMLS_CC) == FAILURE) {
       
   155 +			pefree(entry.filename, entry.is_persistent);
       
   156 +			MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\"");
       
   157  		}
       
   158 +		buffer += len;
       
   159  
       
   160  		entry.offset = entry.offset_abs = offset;
       
   161  		offset += entry.compressed_filesize;
       
   162 diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h
       
   163 index c9306c1..fcfc864 100644
       
   164 --- a/ext/phar/phar_internal.h
       
   165 +++ b/ext/phar/phar_internal.h
       
   166 @@ -654,7 +654,7 @@ int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len,
       
   167  char *phar_find_in_include_path(char *file, int file_len, phar_archive_data **pphar TSRMLS_DC);
       
   168  char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC);
       
   169  phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC);
       
   170 -int phar_parse_metadata(char **buffer, zval **metadata, int zip_metadata_len TSRMLS_DC);
       
   171 +int phar_parse_metadata(char **buffer, zval **metadata, php_uint32 zip_metadata_len TSRMLS_DC);
       
   172  void destroy_phar_manifest_entry(void *pDest);
       
   173  int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position, int follow_links TSRMLS_DC);
       
   174  php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC);