Commit message: Fix bug #69441 (Buffer Overflow when parsing tar/zip/phar in phar_set_inode)
CVE: CVE-2015-3329
CWE: CWE-119
Vulnerability description: Multiple stack-based buffer overflows in the phar_set_inode function in phar_internal.h in PHP before 5.4.40, 5.5.x before 5.5.24, and 5.6.x before 5.6.8 allow remote attackers to execute arbitrary code via a crafted length value in a (1) tar, (2) phar, or (3) ZIP archive.

Project: php-src
File: phar_internal.h

static inline void phar_unixify_path_separators(char *path, int path_len)
{
	char *s;

	/* unixify win paths */
	for (s = path; s - path < path_len; ++s) {
		if (*s == '\\') {
			*s = '/';
		}
	}
}

Project: php-src
File: phar_internal.h

static inline void phar_set_pharufp(phar_archive_data *phar, php_stream *fp TSRMLS_DC)
{
	if (!phar->is_persistent) {
		phar->ufp =  fp;
		return;
	}

	PHAR_GLOBALS->cached_fp[phar->phar_pos].ufp = fp;
}

Project: php-src
File: phar_internal.h

static inline void phar_set_entrypfp(phar_entry_info *entry, php_stream *fp TSRMLS_DC)
{
	if (!entry->phar->is_persistent) {
		entry->phar->fp =  fp;
		return;
	}

	PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].fp = fp;
}

Project: php-src
File: phar_internal.h

static inline void phar_set_fp_type(phar_entry_info *entry, enum phar_fp_type type, off_t offset TSRMLS_DC)
{
	phar_entry_fp_info *data;

	if (!entry->is_persistent) {
		entry->fp_type = type;
		entry->offset = offset;
		return;
	}
	data = &(PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].manifest[entry->manifest_pos]);
	data->fp_type = type;
	data->offset = offset;
}

Project: php-src
File: phar_internal.h

static inline off_t phar_get_fp_offset(phar_entry_info *entry TSRMLS_DC)
{
	if (!entry->is_persistent) {
		return entry->offset;
	}
	if (PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].manifest[entry->manifest_pos].fp_type == PHAR_FP) {
		if (!PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].manifest[entry->manifest_pos].offset) {
			PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].manifest[entry->manifest_pos].offset = entry->offset;
		}
	}
	return PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].manifest[entry->manifest_pos].offset;
}

Project: php-src
File: phar_internal.h

static inline void phar_set_inode(phar_entry_info *entry TSRMLS_DC) /* {{{ */
{
	char tmp[MAXPATHLEN];
	int tmp_len;
	size_t len;

	tmp_len = MIN(MAXPATHLEN, entry->filename_len + entry->phar->fname_len);
	len = MIN(entry->phar->fname_len, tmp_len);
	memcpy(tmp, entry->phar->fname, len);
	len = MIN(tmp_len - len, entry->filename_len);
	memcpy(tmp + entry->phar->fname_len, entry->filename, len);
	entry->inode = (unsigned short)zend_get_hash_value(tmp, tmp_len);
}

Project: php-src
File: phar_internal.h

static inline php_stream *phar_get_pharufp(phar_archive_data *phar TSRMLS_DC)
{
	if (!phar->is_persistent) {
		return phar->ufp;
	}
	return PHAR_GLOBALS->cached_fp[phar->phar_pos].ufp;
}

Project: php-src
File: phar_internal.h

static inline void phar_set_pharfp(phar_archive_data *phar, php_stream *fp TSRMLS_DC)
{
	if (!phar->is_persistent) {
		phar->fp =  fp;
		return;
	}

	PHAR_GLOBALS->cached_fp[phar->phar_pos].fp = fp;
}

Project: php-src
File: phar_internal.h

static inline php_stream *phar_get_entrypfp(phar_entry_info *entry TSRMLS_DC)
{
	if (!entry->is_persistent) {
		return entry->phar->fp;
	}
	return PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].fp;
}

Project: php-src
File: phar_internal.h

static inline enum phar_fp_type phar_get_fp_type(phar_entry_info *entry TSRMLS_DC)
{
	if (!entry->is_persistent) {
		return entry->fp_type;
	}
	return PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].manifest[entry->manifest_pos].fp_type;
}

Project: php-src
File: phar_internal.h

static inline size_t phar_stream_copy_to_stream(php_stream *src, php_stream *dest, size_t maxlen, size_t *len STREAMS_DC TSRMLS_DC)
{
	size_t ret = php_stream_copy_to_stream(src, dest, maxlen);
	if (len) {
		*len = ret;
	}
	if (ret) {
		return SUCCESS;
	}
	return FAILURE;
}

Project: php-src
File: phar_internal.h

static inline int phar_find_key(HashTable *_SERVER, char *key, int len, void **stuff TSRMLS_DC)
{
	if (SUCCESS == zend_hash_find(_SERVER, key, len, stuff)) {
		return 1;
	} else {
		int s = len;
		zstr var;
		s = phar_make_unicode(&var, key, len TSRMLS_CC);
		if (SUCCESS == zend_u_hash_find(_SERVER, IS_UNICODE, var, s, stuff)) {
			efree(var.u);
			return 1;
		}
		efree(var.u);
		return 0;
	}
}

Project: php-src
File: phar_internal.h

static inline void phar_set_entrypufp(phar_entry_info *entry, php_stream *fp TSRMLS_DC)
{
	if (!entry->phar->is_persistent) {
		entry->phar->ufp =  fp;
		return;
	}

	PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].ufp = fp;
}

Project: php-src
File: phar_internal.h

static inline int phar_make_unicode(zstr *c_var, char *arKey, uint nKeyLength TSRMLS_DC)
{
	int c_var_len;
	UConverter *conv = ZEND_U_CONVERTER(UG(runtime_encoding_conv));

	c_var->u = NULL;
	if (zend_string_to_unicode(conv, &c_var->u, &c_var_len, arKey, nKeyLength TSRMLS_CC) == FAILURE) {

		if (c_var->u) {
			efree(c_var->u);
		}
		return 0;

	}
	return c_var_len;
}

Project: php-src
File: phar_internal.h

static inline php_stream *phar_get_entrypufp(phar_entry_info *entry TSRMLS_DC)
{
	if (!entry->is_persistent) {
		return entry->phar->ufp;
	}
	return PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].ufp;
}

Project: php-src
File: phar_internal.h

static inline int phar_validate_alias(const char *alias, int alias_len) /* {{{ */
{
	return !(memchr(alias, '/', alias_len) || memchr(alias, '\\', alias_len) || memchr(alias, ':', alias_len) ||
		memchr(alias, ';', alias_len) || memchr(alias, '\n', alias_len) || memchr(alias, '\r', alias_len));
}

Project: php-src
File: phar_internal.h

static inline php_stream *phar_get_pharfp(phar_archive_data *phar TSRMLS_DC)
{
	if (!phar->is_persistent) {
		return phar->fp;
	}
	return PHAR_GLOBALS->cached_fp[phar->phar_pos].fp;
}