Skip to content

Commit

Permalink
Merge branch 'PHP-7.0.3' into PHP-7.0
Browse files Browse the repository at this point in the history
* PHP-7.0.3: (35 commits)
  fix tests
  update NEWS
  fix tests
  fix NEWS
  Update NEWS
  update NEWS
  Fixed bug #71475: openssl_seal() uninitialized memory usage
  Fixed bug #71488: Stack overflow when decompressing tar archives
  fix tests
  fix wrong gc sequence
  revert the API string as well
  update NEWS
  Revert "Fix #70720"
  sync NEWS
  reset ext/session to the state of 7.0.2
  update NEWS
  update NEWS
  add missing headers for SIZE_MAX
  backport the escapeshell* functions hardening branch
  add tests
  ...

Conflicts:
	configure.in
	ext/session/tests/bug69111.phpt
	main/php_version.h
  • Loading branch information
smalyshev committed Feb 2, 2016
2 parents 2764586 + 0fca0d9 commit c631f1e
Show file tree
Hide file tree
Showing 49 changed files with 619 additions and 320 deletions.
3 changes: 2 additions & 1 deletion ext/openssl/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -4942,6 +4942,7 @@ PHP_FUNCTION(openssl_seal)
memset(eks, 0, sizeof(*eks) * nkeys);
key_resources = safe_emalloc(nkeys, sizeof(zend_resource*), 0);
memset(key_resources, 0, sizeof(zend_resource*) * nkeys);
memset(pkeys, 0, sizeof(*pkeys) * nkeys);

/* get the public keys we are using to seal this data */
i = 0;
Expand Down Expand Up @@ -5003,7 +5004,7 @@ PHP_FUNCTION(openssl_seal)

clean_exit:
for (i=0; i<nkeys; i++) {
if (key_resources[i] == NULL) {
if (key_resources[i] == NULL && pkeys[i] != NULL) {
EVP_PKEY_free(pkeys[i]);
}
if (eks[i]) {
Expand Down
16 changes: 16 additions & 0 deletions ext/openssl/tests/bug71475.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
Bug #71475: openssl_seal() uninitialized memory usage
--SKIPIF--
<?php
if (!extension_loaded("openssl")) die("skip openssl not loaded");
?>
--FILE--
<?php
$_ = str_repeat("A", 512);
openssl_seal($_, $_, $_, array_fill(0,64,0));
?>
DONE
--EXPECTF--

Warning: openssl_seal(): not a public key (1th member of pubkeys) in %s/bug71475.php on line %d
DONE
3 changes: 2 additions & 1 deletion ext/phar/dirstream.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,13 +199,14 @@ static php_stream *phar_make_dirstream(char *dir, HashTable *manifest) /* {{{ */
zend_hash_internal_pointer_reset(manifest);

while (FAILURE != zend_hash_has_more_elements(manifest)) {
keylen = 0;
if (HASH_KEY_NON_EXISTENT == zend_hash_get_current_key(manifest, &str_key, &unused)) {
break;
}

keylen = ZSTR_LEN(str_key);
if (keylen <= (uint)dirlen) {
if (keylen < (uint)dirlen || !strncmp(ZSTR_VAL(str_key), dir, dirlen)) {
if (keylen == 0 || keylen < (uint)dirlen || !strncmp(ZSTR_VAL(str_key), dir, dirlen)) {
if (SUCCESS != zend_hash_move_forward(manifest)) {
break;
}
Expand Down
24 changes: 17 additions & 7 deletions ext/phar/tar.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,13 @@ static int phar_tar_process_metadata(phar_entry_info *entry, php_stream *fp) /*
}
/* }}} */

#if !HAVE_STRNLEN
static size_t strnlen(const char *s, size_t maxlen) {
char *r = (char *)memchr(s, '\0', maxlen);
return r ? r-s : maxlen;
}
#endif

int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, phar_archive_data** pphar, int is_data, php_uint32 compression, char **error) /* {{{ */
{
char buf[512], *actual_alias = NULL, *p;
Expand All @@ -204,6 +211,7 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
php_uint32 sum1, sum2, size, old;
phar_archive_data *myphar, *actual;
int last_was_longlink = 0;
int linkname_len;

if (error) {
*error = NULL;
Expand Down Expand Up @@ -264,7 +272,7 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
goto next;
}

if (((!old && hdr->prefix[0] == 0) || old) && strlen(hdr->name) == sizeof(".phar/signature.bin")-1 && !strncmp(hdr->name, ".phar/signature.bin", sizeof(".phar/signature.bin")-1)) {
if (((!old && hdr->prefix[0] == 0) || old) && strnlen(hdr->name, 100) == sizeof(".phar/signature.bin")-1 && !strncmp(hdr->name, ".phar/signature.bin", sizeof(".phar/signature.bin")-1)) {
zend_off_t curloc;

if (size > 511) {
Expand Down Expand Up @@ -348,7 +356,7 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
entry.filename_len = entry.uncompressed_filesize;

/* Check for overflow - bug 61065 */
if (entry.filename_len == UINT_MAX) {
if (entry.filename_len == UINT_MAX || entry.filename_len == 0) {
if (error) {
spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (invalid entry size)", fname);
}
Expand Down Expand Up @@ -472,20 +480,22 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
}

entry.link = NULL;

/* link field is null-terminated unless it has 100 non-null chars.
* Thus we can not use strlen. */
linkname_len = strnlen(hdr->linkname, 100);
if (entry.tar_type == TAR_LINK) {
if (!zend_hash_str_exists(&myphar->manifest, hdr->linkname, strlen(hdr->linkname))) {
if (!zend_hash_str_exists(&myphar->manifest, hdr->linkname, linkname_len)) {
if (error) {
spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file - hard link to non-existent file \"%s\"", fname, hdr->linkname);
spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file - hard link to non-existent file \"%.*s\"", fname, linkname_len, hdr->linkname);
}
pefree(entry.filename, entry.is_persistent);
php_stream_close(fp);
phar_destroy_phar_data(myphar);
return FAILURE;
}
entry.link = estrdup(hdr->linkname);
entry.link = estrndup(hdr->linkname, linkname_len);
} else if (entry.tar_type == TAR_SYMLINK) {
entry.link = estrdup(hdr->linkname);
entry.link = estrndup(hdr->linkname, linkname_len);
}
phar_set_inode(&entry);
if ((newentry = zend_hash_str_add_mem(&myphar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info))) == NULL) {
Expand Down
15 changes: 15 additions & 0 deletions ext/phar/tests/bug71331.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
Bug #71331 (Uninitialized pointer in phar_make_dirstream())
--SKIPIF--
<?php if (!extension_loaded("phar")) die("skip"); ?>
--FILE--
<?php
$p = new PharData(__DIR__."/bug71331.tar");
?>
DONE
--EXPECTF--
Fatal error: Uncaught UnexpectedValueException: phar error: "%s/bug71331.tar" is a corrupted tar file (invalid entry size) in %s/bug71331.php:2
Stack trace:
#0 %s/bug71331.php(2): PharData->__construct('%s')
#1 {main}
thrown in %s/bug71331.php on line 2
Binary file added ext/phar/tests/bug71331.tar
Binary file not shown.
13 changes: 13 additions & 0 deletions ext/phar/tests/bug71354.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
Phar: bug #71354: Heap corruption in tar/zip/phar parser.
--SKIPIF--
<?php if (!extension_loaded("phar")) die("skip"); ?>
--FILE--
<?php
$p = new PharData(__DIR__."/bug71354.tar");
var_dump($p['aaaa']->getContent());
?>
DONE
--EXPECT--
string(0) ""
DONE
Binary file added ext/phar/tests/bug71354.tar
Binary file not shown.
18 changes: 18 additions & 0 deletions ext/phar/tests/bug71391.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
Phar: bug #71391: NULL Pointer Dereference in phar_tar_setupmetadata()
--SKIPIF--
<?php if (!extension_loaded("phar")) die("skip"); ?>
--FILE--
<?php
// duplicate since the tar will change
copy(__DIR__."/bug71391.tar", __DIR__."/bug71391.test.tar");
$p = new PharData(__DIR__."/bug71391.test.tar");
$p->delMetaData();
?>
DONE
--CLEAN--
<?php
unlink(__DIR__."/bug71391.test.tar");
?>
--EXPECT--
DONE
Binary file added ext/phar/tests/bug71391.tar
Binary file not shown.
16 changes: 16 additions & 0 deletions ext/phar/tests/bug71488.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
Phar: bug #71488: Stack overflow when decompressing tar archives
--SKIPIF--
<?php if (!extension_loaded("phar")) die("skip"); ?>
--FILE--
<?php
$p = new PharData(__DIR__."/bug71488.tar");
$newp = $p->decompress("test");
?>
DONE
--CLEAN--
<?php
@unlink(__DIR__."/bug71488.test");
?>
--EXPECT--
DONE
Binary file added ext/phar/tests/bug71488.tar
Binary file not shown.
1 change: 1 addition & 0 deletions ext/spl/spl_array.c
Original file line number Diff line number Diff line change
Expand Up @@ -1778,6 +1778,7 @@ SPL_METHOD(Array, unserialize)
intern->ar_flags &= ~SPL_ARRAY_CLONE_MASK;
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)) {
goto outexcept;
}
Expand Down
2 changes: 2 additions & 0 deletions ext/spl/spl_observer.c
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,9 @@ SPL_METHOD(SplObjectStorage, unserialize)
var_replace(&var_hash, &entry, &element->obj);
var_replace(&var_hash, &inf, &element->inf);
zval_ptr_dtor(&entry);
ZVAL_UNDEF(&entry);
zval_ptr_dtor(&inf);
ZVAL_UNDEF(&inf);
}

if (*p != ';') {
Expand Down
1 change: 1 addition & 0 deletions ext/standard/basic_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -3657,6 +3657,7 @@ PHP_MINIT_FUNCTION(basic) /* {{{ */
#ifdef PHP_CAN_SUPPORT_PROC_OPEN
BASIC_MINIT_SUBMODULE(proc_open)
#endif
BASIC_MINIT_SUBMODULE(exec)

BASIC_MINIT_SUBMODULE(user_streams)
BASIC_MINIT_SUBMODULE(imagetypes)
Expand Down
64 changes: 59 additions & 5 deletions ext/standard/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,32 @@
#include <fcntl.h>
#endif

#if HAVE_NICE && HAVE_UNISTD_H
#if HAVE_UNISTD_H
#include <unistd.h>
#endif

static int cmd_max_len;

/* {{{ PHP_MINIT_FUNCTION(exec) */
PHP_MINIT_FUNCTION(exec)
{
#ifdef _SC_ARG_MAX
cmd_max_len = sysconf(_SC_ARG_MAX);
#elif defined(ARG_MAX)
cmd_max_len = ARG_MAX;
#elif defined(PHP_WIN32)
/* Executed commands will run through cmd.exe. As long as it's the case,
it's just the constant limit.*/
cmd_max_len = 8192;
#else
/* This is just an arbitrary value for the fallback case. */
cmd_max_len = 4096;
#endif

return SUCCESS;
}
/* }}} */

/* {{{ php_exec
* If type==0, only last line of output is returned (exec)
* If type==1, all lines will be printed and last lined returned (system)
Expand Down Expand Up @@ -245,13 +267,19 @@ PHP_FUNCTION(passthru)
*/
PHPAPI zend_string *php_escape_shell_cmd(char *str)
{
register int x, y, l = (int)strlen(str);
size_t estimate = (2 * l) + 1;
register int x, y;
size_t l = strlen(str);
uint64_t estimate = (2 * (uint64_t)l) + 1;
zend_string *cmd;
#ifndef PHP_WIN32
char *p = NULL;
#endif

/* max command line length - two single quotes - \0 byte length */
if (l > cmd_max_len - 2 - 1) {
php_error_docref(NULL, E_ERROR, "Command exceeds the allowed length of %d bytes", cmd_max_len);
return ZSTR_EMPTY_ALLOC();
}

cmd = zend_string_safe_alloc(2, l, 0, 0);

Expand Down Expand Up @@ -324,6 +352,12 @@ PHPAPI zend_string *php_escape_shell_cmd(char *str)
}
ZSTR_VAL(cmd)[y] = '\0';

if (y - 1 > cmd_max_len) {
php_error_docref(NULL, E_ERROR, "Escaped command exceeds the allowed length of %d bytes", cmd_max_len);
zend_string_release(cmd);
return ZSTR_EMPTY_ALLOC();
}

if ((estimate - y) > 4096) {
/* realloc if the estimate was way overill
* Arbitrary cutoff point of 4096 */
Expand All @@ -340,10 +374,16 @@ PHPAPI zend_string *php_escape_shell_cmd(char *str)
*/
PHPAPI zend_string *php_escape_shell_arg(char *str)
{
int x, y = 0, l = (int)strlen(str);
int x, y = 0;
size_t l = strlen(str);
zend_string *cmd;
size_t estimate = (4 * l) + 3;
uint64_t estimate = (4 * (uint64_t)l) + 3;

/* max command line length - two single quotes - \0 byte length */
if (l > cmd_max_len - 2 - 1) {
php_error_docref(NULL, E_ERROR, "Argument exceeds the allowed length of %d bytes", cmd_max_len);
return ZSTR_EMPTY_ALLOC();
}

cmd = zend_string_safe_alloc(4, l, 2, 0); /* worst case */

Expand Down Expand Up @@ -399,6 +439,12 @@ PHPAPI zend_string *php_escape_shell_arg(char *str)
#endif
ZSTR_VAL(cmd)[y] = '\0';

if (y - 1 > cmd_max_len) {
php_error_docref(NULL, E_ERROR, "Escaped argument exceeds the allowed length of %d bytes", cmd_max_len);
zend_string_release(cmd);
return ZSTR_EMPTY_ALLOC();
}

if ((estimate - y) > 4096) {
/* realloc if the estimate was way overill
* Arbitrary cutoff point of 4096 */
Expand All @@ -421,6 +467,10 @@ PHP_FUNCTION(escapeshellcmd)
}

if (command_len) {
if (command_len != strlen(command)) {
php_error_docref(NULL, E_ERROR, "Input string contains NULL bytes");
return;
}
RETVAL_STR(php_escape_shell_cmd(command));
} else {
RETVAL_EMPTY_STRING();
Expand All @@ -440,6 +490,10 @@ PHP_FUNCTION(escapeshellarg)
}

if (argument) {
if (argument_len != strlen(argument)) {
php_error_docref(NULL, E_ERROR, "Input string contains NULL bytes");
return;
}
RETVAL_STR(php_escape_shell_arg(argument));
}
}
Expand Down
1 change: 1 addition & 0 deletions ext/standard/exec.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ PHP_FUNCTION(proc_close);
PHP_FUNCTION(proc_terminate);
PHP_FUNCTION(proc_nice);
PHP_MINIT_FUNCTION(proc_open);
PHP_MINIT_FUNCTION(exec);

PHPAPI zend_string *php_escape_shell_cmd(char *);
PHPAPI zend_string *php_escape_shell_arg(char *);
Expand Down
16 changes: 15 additions & 1 deletion ext/standard/iptc.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@

#include <sys/stat.h>

#ifdef PHP_WIN32
# include "win32/php_stdint.h"
#else
# if HAVE_INTTYPES_H
# include <inttypes.h>
# elif HAVE_STDINT_H
# include <stdint.h>
# endif
#endif

/* some defines for the different JPEG block types */
#define M_SOF0 0xC0 /* Start Of Frame N */
Expand Down Expand Up @@ -196,6 +205,11 @@ PHP_FUNCTION(iptcembed)
RETURN_FALSE;
}

if (iptcdata_len >= SIZE_MAX - sizeof(psheader) - 1025) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "IPTC data too large");
RETURN_FALSE;
}

if ((fp = VCWD_FOPEN(jpeg_file, "rb")) == 0) {
php_error_docref(NULL, E_WARNING, "Unable to open %s", jpeg_file);
RETURN_FALSE;
Expand All @@ -204,7 +218,7 @@ PHP_FUNCTION(iptcembed)
if (spool < 2) {
zend_fstat(fileno(fp), &sb);

spoolbuf = zend_string_alloc(iptcdata_len + sizeof(psheader) + sb.st_size + 1024, 0);
spoolbuf = zend_string_safe_alloc(1, iptcdata_len + sizeof(psheader) + 1024 + 1, sb.st_size, 0);
poi = (unsigned char*)ZSTR_VAL(spoolbuf);
memset(poi, 0, iptcdata_len + sizeof(psheader) + sb.st_size + 1024 + 1);
}
Expand Down
Loading

0 comments on commit c631f1e

Please sign in to comment.