diff options
Diffstat (limited to 'debian-php-7.1.33.patch')
-rw-r--r-- | debian-php-7.1.33.patch | 1890 |
1 files changed, 1890 insertions, 0 deletions
diff --git a/debian-php-7.1.33.patch b/debian-php-7.1.33.patch new file mode 100644 index 000000000000..06129eafbb06 --- /dev/null +++ b/debian-php-7.1.33.patch @@ -0,0 +1,1890 @@ + +diff --git a/ext/standard/proc_open.c b/ext/standard/proc_open.c +index 17dcdb1..5c1d514 100644 +--- a/ext/standard/proc_open.c ++++ b/ext/standard/proc_open.c +@@ -62,7 +62,7 @@ + * */ + #ifdef PHP_CAN_SUPPORT_PROC_OPEN + +-#if 0 && HAVE_PTSNAME && HAVE_GRANTPT && HAVE_UNLOCKPT && HAVE_SYS_IOCTL_H && HAVE_TERMIOS_H ++#if HAVE_PTSNAME && HAVE_GRANTPT && HAVE_UNLOCKPT && HAVE_SYS_IOCTL_H && HAVE_TERMIOS_H + # include <sys/ioctl.h> + # include <termios.h> + # define PHP_CAN_DO_PTS 1 +diff --git a/php.ini-development b/php.ini-development +index 654968b..d78d2f4 100644 +--- a/php.ini-development ++++ b/php.ini-development +@@ -306,6 +306,12 @@ + ; and below. This directive makes most sense if used in a per-directory + ; or per-virtualhost web server configuration file. + ; http://php.net/open-basedir ++ ++; NOTE: this is considered a "broken" security measure. ++; Applications relying on this feature will not receive full ++; support by the security team. For more information please ++; see /usr/share/doc/php-common/README.Debian.security ++; + ;open_basedir = + + ; This directive allows you to disable certain functions for security reasons. +diff --git a/ext/dba/config.m4 b/ext/dba/config.m4 +index ced02de..64e1661 100644 +--- a/ext/dba/config.m4 ++++ b/ext/dba/config.m4 +@@ -312,61 +312,13 @@ + dbdp4="/usr/local/BerkeleyDB.4." + dbdp5="/usr/local/BerkeleyDB.5." + for i in $PHP_DB4 ${dbdp5}1 ${dbdp5}0 ${dbdp4}8 ${dbdp4}7 ${dbdp4}6 ${dbdp4}5 ${dbdp4}4 ${dbdp4}3 ${dbdp4}2 ${dbdp4}1 ${dbdp}0 /usr/local /usr; do +- if test -f "$i/db5/db.h"; then +- THIS_PREFIX=$i +- THIS_INCLUDE=$i/db5/db.h +- break +- elif test -f "$i/db4/db.h"; then +- THIS_PREFIX=$i +- THIS_INCLUDE=$i/db4/db.h +- break +- elif test -f "$i/include/db5.3/db.h"; then +- THIS_PREFIX=$i +- THIS_INCLUDE=$i/include/db5.3/db.h +- break +- elif test -f "$i/include/db5.1/db.h"; then +- THIS_PREFIX=$i +- THIS_INCLUDE=$i/include/db5.1/db.h +- break +- elif test -f "$i/include/db5.0/db.h"; then +- THIS_PREFIX=$i +- THIS_INCLUDE=$i/include/db5.0/db.h +- break +- elif test -f "$i/include/db4.8/db.h"; then +- THIS_PREFIX=$i +- THIS_INCLUDE=$i/include/db4.8/db.h +- break +- elif test -f "$i/include/db4.7/db.h"; then +- THIS_PREFIX=$i +- THIS_INCLUDE=$i/include/db4.7/db.h +- break +- elif test -f "$i/include/db4.6/db.h"; then +- THIS_PREFIX=$i +- THIS_INCLUDE=$i/include/db4.6/db.h +- break +- elif test -f "$i/include/db4.5/db.h"; then +- THIS_PREFIX=$i +- THIS_INCLUDE=$i/include/db4.5/db.h +- break +- elif test -f "$i/include/db4/db.h"; then +- THIS_PREFIX=$i +- THIS_INCLUDE=$i/include/db4/db.h +- break +- elif test -f "$i/include/db/db4.h"; then +- THIS_PREFIX=$i +- THIS_INCLUDE=$i/include/db/db4.h +- break +- elif test -f "$i/include/db4.h"; then +- THIS_PREFIX=$i +- THIS_INCLUDE=$i/include/db4.h +- break +- elif test -f "$i/include/db.h"; then ++ if test -f "$i/include/db.h"; then + THIS_PREFIX=$i + THIS_INCLUDE=$i/include/db.h + break + fi + done +- PHP_DBA_DB_CHECK(4, db-5.3 db-5.1 db-5.0 db-4.8 db-4.7 db-4.6 db-4.5 db-4.4 db-4.3 db-4.2 db-4.1 db-4.0 db-4 db4 db, [(void)db_create((DB**)0, (DB_ENV*)0, 0)]) ++ PHP_DBA_DB_CHECK(4, db, [(void)db_create((DB**)0, (DB_ENV*)0, 0)]) + fi + PHP_DBA_STD_RESULT(db4,Berkeley DB4) + +diff --git a/ext/dba/dba.c b/ext/dba/dba.c +index a36c679..b2de3b2 100644 +--- a/ext/dba/dba.c ++++ b/ext/dba/dba.c +@@ -52,6 +52,10 @@ + #include "php_qdbm.h" + #include "php_tcadb.h" + ++#ifdef DB4_INCLUDE_FILE ++#include DB4_INCLUDE_FILE ++#endif ++ + /* {{{ arginfo */ + ZEND_BEGIN_ARG_INFO_EX(arginfo_dba_popen, 0, 0, 2) + ZEND_ARG_INFO(0, path) +@@ -552,6 +556,10 @@ + + php_info_print_table_start(); + php_info_print_table_row(2, "DBA support", "enabled"); ++#ifdef DB_VERSION_STRING ++ php_info_print_table_row(2, "libdb header version", DB_VERSION_STRING); ++ php_info_print_table_row(2, "libdb library version", db_version(NULL, NULL, NULL)); ++#endif + if (handlers.s) { + smart_str_0(&handlers); + php_info_print_table_row(2, "Supported handlers", ZSTR_VAL(handlers.s)); +diff --git a/ext/mysqli/config.m4 b/ext/mysqli/config.m4 +index c5dfe5d..87dd43e 100644 +--- a/ext/mysqli/config.m4 ++++ b/ext/mysqli/config.m4 +@@ -59,7 +59,7 @@ + MYSQL_LIB_CFG='--libmysqld-libs' + dnl mysqlnd doesn't support embedded, so we have to add some extra stuff + mysqli_extra_sources="mysqli_embedded.c" +- elif test "$enable_maintainer_zts" = "yes"; then ++ elif true || test "$enable_maintainer_zts" = "yes"; then + MYSQL_LIB_CFG='--libs_r' + MYSQL_LIB_NAME='mysqlclient_r' + else +diff --git a/ext/pdo_mysql/config.m4 b/ext/pdo_mysql/config.m4 +index 96f0441..6828e1d 100755 +--- a/ext/pdo_mysql/config.m4 ++++ b/ext/pdo_mysql/config.m4 +@@ -67,7 +67,7 @@ + if test "x$SED" = "x"; then + AC_PATH_PROG(SED, sed) + fi +- if test "$enable_maintainer_zts" = "yes"; then ++ if true || test "$enable_maintainer_zts" = "yes"; then + PDO_MYSQL_LIBNAME=mysqlclient_r + PDO_MYSQL_LIBS=`$PDO_MYSQL_CONFIG --libs_r | $SED -e "s/'//g"` + else +--- /dev/null ++++ b/tests/func/null-new_val.phpt +@@ -0,0 +1,10 @@ ++--TEST-- ++ini_restore strcmp NULL new_val ++--FILE-- ++<?php ++ ++ini_set('error_log','ini_set_works'); ++ini_restore('error_log'); ++ ++?> ++--EXPECT-- +diff --git a/build/build.mk b/build/build.mk +index 1ce958f..b8c7492 100644 +--- a/build/build.mk ++++ b/build/build.mk +@@ -63,6 +63,5 @@ + @if (test ! -f '.git/info/exclude' || grep -s "git-ls-files" .git/info/exclude); then \ + (echo "Rebuild .git/info/exclude" && echo '*.o' > .git/info/exclude && git svn propget svn:ignore | grep -v config.nice >> .git/info/exclude); \ + fi; \ +- git clean -X -f -d; + + .PHONY: $(ALWAYS) snapshot +diff --git a/ext/dba/config.m4 b/ext/dba/config.m4 +index 64e1661..edc7d11 100644 +--- a/ext/dba/config.m4 ++++ b/ext/dba/config.m4 +@@ -113,6 +113,10 @@ + THIS_PREFIX=$i + THIS_INCLUDE=$i/include/depot.h + break ++ elif test -f "$i/include/qdbm/depot.h"; then ++ THIS_PREFIX=$i ++ THIS_INCLUDE=$i/include/qdbm/depot.h ++ break + fi + done + +diff --git a/sapi/fpm/php-fpm.8.in b/sapi/fpm/php-fpm.8.in +index 86edaa8..19e66a0 100644 +--- a/sapi/fpm/php-fpm.8.in ++++ b/sapi/fpm/php-fpm.8.in +@@ -139,22 +139,8 @@ + .TP + .B php.ini + The standard php configuration file. +-.SH EXAMPLES +-For any unix systems which use init.d for their main process manager, you should use the init script provided to start and stop the php-fpm daemon. +-.P +-.PD 1 +-.RS +-sudo /etc/init.d/php-fpm start +-.RE +-.TP +-For any unix systems which use systemd for their main process manager, you should use the unit file provided to start and stop the php-fpm daemon. +-.P +-.PD 1 +-.RS +-sudo systemctl start php-fpm.service +-.RE +-.TP +-If your installation has no appropriate init script, launch php-fpm with no arguments. It will launch as a daemon (background process) by default. The file @php_fpm_localstatedir@/run/php-fpm.pid determines whether php-fpm is already up and running. Once started, php-fpm then responds to several POSIX signals: ++.SH SIGNAL ++Once started, php-fpm then responds to several POSIX signals: + .P + .PD 0 + .RS +@@ -168,10 +154,6 @@ + .RE + .PD 1 + .P +-.SH TIPS +-The PHP-FPM CGI daemon will work well with most popular webservers, including Apache2, lighttpd and nginx. +-.PD 1 +-.P + .SH SEE ALSO + The PHP-FPM website: + .PD 0 +diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c +index 7fdf906..76dd0dd 100644 +--- a/main/streams/plain_wrapper.c ++++ b/main/streams/plain_wrapper.c +@@ -693,7 +693,13 @@ + + switch (value) { + case PHP_STREAM_MMAP_SUPPORTED: +- return fd == -1 ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK; ++ if (fd == -1) ++ return PHP_STREAM_OPTION_RETURN_ERR; ++ /* Don't mmap large files */ ++ do_fstat(data, 1); ++ if (data->sb.st_size > 4 * 1024 * 1024) ++ return PHP_STREAM_OPTION_RETURN_ERR; ++ return PHP_STREAM_OPTION_RETURN_OK; + + case PHP_STREAM_MMAP_MAP_RANGE: + if(do_fstat(data, 1) != 0) { +diff --git a/ext/dba/dba.c b/ext/dba/dba.c +index b2de3b2..51c5ccf 100644 +--- a/ext/dba/dba.c ++++ b/ext/dba/dba.c +@@ -940,7 +940,7 @@ + } + } + +- if (error || hptr->open(info, &error) != SUCCESS) { ++ if (error || (hptr->open)(info, &error) != SUCCESS) { + dba_close(info); + php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Driver initialization failed for handler: %s%s%s", hptr->name, error?": ":"", error?error:""); + FREENOW; +diff --git a/ext/dba/dba_db3.c b/ext/dba/dba_db3.c +index dd1bcb8..aca3c93 100644 +--- a/ext/dba/dba_db3.c ++++ b/ext/dba/dba_db3.c +@@ -96,9 +96,9 @@ + dbp->set_errcall(dbp, php_dba_db3_errcall_fcn); + if( + #if (DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)) +- (err=dbp->open(dbp, 0, info->path, NULL, type, gmode, filemode)) == 0) { ++ (err=(dbp->open)(dbp, 0, info->path, NULL, type, gmode, filemode)) == 0) { + #else +- (err=dbp->open(dbp, info->path, NULL, type, gmode, filemode)) == 0) { ++ (err=(dbp->open)(dbp, info->path, NULL, type, gmode, filemode)) == 0) { + #endif + dba_db3_data *data; + +diff --git a/ext/dba/dba_db4.c b/ext/dba/dba_db4.c +index 63a69bd..a77cc22 100644 +--- a/ext/dba/dba_db4.c ++++ b/ext/dba/dba_db4.c +@@ -125,9 +125,9 @@ + dbp->set_errcall(dbp, php_dba_db4_errcall_fcn); + if ( + #if (DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)) +- (err=dbp->open(dbp, 0, info->path, NULL, type, gmode, filemode)) == 0) { ++ (err=(dbp->open)(dbp, 0, info->path, NULL, type, gmode, filemode)) == 0) { + #else +- (err=dbp->open(dbp, info->path, NULL, type, gmode, filemode)) == 0) { ++ (err=(dbp->open)(dbp, info->path, NULL, type, gmode, filemode)) == 0) { + #endif + dba_db4_data *data; + +diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c +index ad825ce..50d8f34 100644 +--- a/ext/zlib/zlib.c ++++ b/ext/zlib/zlib.c +@@ -49,6 +49,18 @@ + int le_deflate; + int le_inflate; + ++/* ++ * zlib include files can define the following preprocessor defines which rename ++ * the corresponding PHP functions to gzopen64, gzseek64 and gztell64 and thereby ++ * breaking some software, most notably PEAR's Archive_Tar, which halts execution ++ * without error message on gzip compressed archivesa. ++ * ++ * This only seems to happen on 32bit systems with large file support. ++ */ ++#undef gzopen ++#undef gzseek ++#undef gztell ++ + ZEND_DECLARE_MODULE_GLOBALS(zlib); + + /* {{{ Memory management wrappers */ +diff --git a/ext/standard/tests/strings/setlocale_variation2.phpt b/ext/standard/tests/strings/setlocale_variation2.phpt +index fad3298..346c987 100644 +--- a/ext/standard/tests/strings/setlocale_variation2.phpt ++++ b/ext/standard/tests/strings/setlocale_variation2.phpt +@@ -55,6 +55,7 @@ + //try different locale names + $failure_locale = array(); + $success_count = 0; ++$expected = 0; + + echo "-- Test setlocale() with all available locale in the system --\n"; + // gather all locales installed in the system(stored $all_system_locales), +@@ -64,6 +65,10 @@ + if(setlocale(LC_ALL,$value )){ + $success_count++; + } ++ else if ($value == 'no_NO.ISO-8859-1') { ++ // ignore this one, see rhbz #971416 ++ $expected++; ++ } + else{ + //failure values are put in to an array $failure_locale + $failure_locale[] = $value; +@@ -72,11 +77,11 @@ + + echo "No of locales found on the machine = ".count($all_system_locales)."\n"; + echo "No of setlocale() success = ".$success_count."\n"; +-echo "Expected no of failures = 0\n"; ++echo "Expected no of failures = $expected\n"; + echo "Test "; + // check if there were any failure of setlocale() function earlier, if any + // failure then dump the list of failing locales +-if($success_count != count($all_system_locales)){ ++if($success_count + $expected != count($all_system_locales)){ + echo "FAILED\n"; + echo "Names of locale() for which setlocale() failed ...\n"; + var_dump($failure_locale); +@@ -92,6 +97,6 @@ + -- Test setlocale() with all available locale in the system -- + No of locales found on the machine = %d + No of setlocale() success = %d +-Expected no of failures = 0 ++Expected no of failures = %d + Test PASSED + Done +diff --git a/ext/pcre/tests/bug37911.phpt b/ext/pcre/tests/bug37911.phpt +index 2b7481a..0d2859d 100644 +--- a/ext/pcre/tests/bug37911.phpt ++++ b/ext/pcre/tests/bug37911.phpt +@@ -37,5 +37,5 @@ + string(4) "blub" + } + +-Warning: preg_replace_callback(): Compilation failed: group name must start with a non-digit at offset %d in %sbug37911.php on line %d ++Warning: preg_replace_callback(): Numeric named subpatterns are not allowed in %sbug37911.php on line %d + NULL +diff --git a/ext/pcre/tests/grep2.phpt b/ext/pcre/tests/grep2.phpt +index 1a8476c..0cf8d4a 100644 +--- a/ext/pcre/tests/grep2.phpt ++++ b/ext/pcre/tests/grep2.phpt +@@ -40,12 +40,6 @@ + string(1) "1" + } + bool(true) +-array(3) { +- [5]=> +- string(1) "a" +- ["xyz"]=> +- string(2) "q6" +- [6]=> +- string(3) "h20" ++array(0) { + } +-bool(false) ++bool(true) +diff --git a/ext/pcre/tests/match_flags3.phpt b/ext/pcre/tests/match_flags3.phpt +index 695f0c1..05c62a0 100644 +--- a/ext/pcre/tests/match_flags3.phpt ++++ b/ext/pcre/tests/match_flags3.phpt +@@ -41,5 +41,5 @@ + } + } + +-Warning: preg_match(): Compilation failed: group name must start with a non-digit at offset %d in %smatch_flags3.php on line %d ++Warning: preg_match(): Numeric named subpatterns are not allowed in %smatch_flags3.php on line %d + bool(false) +diff --git a/ext/curl/config.m4 b/ext/curl/config.m4 +index 1ad688f..59fb585 100644 +--- a/ext/curl/config.m4 ++++ b/ext/curl/config.m4 +@@ -6,12 +6,12 @@ + [ --with-curl[=DIR] Include cURL support]) + + if test "$PHP_CURL" != "no"; then +- if test -r $PHP_CURL/include/curl/easy.h; then ++ if test -r $PHP_CURL/include/$DEB_HOST_MULTIARCH/curl/easy.h || test -r $PHP_CURL/include/curl/easy.h; then + CURL_DIR=$PHP_CURL + else + AC_MSG_CHECKING(for cURL in default path) + for i in /usr/local /usr; do +- if test -r $i/include/curl/easy.h; then ++ if test -r $i/include/$DEB_HOST_MULTIARCH/curl/easy.h || test -r $i/include/curl/easy.h; then + CURL_DIR=$i + AC_MSG_RESULT(found in $i) + break +diff --git a/ext/readline/config.m4 b/ext/readline/config.m4 +index d63df8b..62e873b 100644 +--- a/ext/readline/config.m4 ++++ b/ext/readline/config.m4 +@@ -67,6 +67,13 @@ + -L$READLINE_DIR/$PHP_LIBDIR $PHP_READLINE_LIBS + ]) + ++ PHP_CHECK_LIBRARY(readline, rl_completion_matches, ++ [ ++ AC_DEFINE(HAVE_RL_COMPLETION_MATCHES, 1, [ ]) ++ ],[],[ ++ -L$READLINE_DIR/$PHP_LIBDIR $PHP_READLINE_LIBS ++ ]) ++ + AC_DEFINE(HAVE_LIBREADLINE, 1, [ ]) + + elif test "$PHP_LIBEDIT" != "no"; then +@@ -114,11 +121,17 @@ + -L$READLINE_DIR/$PHP_LIBDIR + ]) + ++ PHP_CHECK_LIBRARY(edit, rl_completion_matches, ++ [ ++ AC_DEFINE(HAVE_RL_COMPLETION_MATCHES, 1, [ ]) ++ ],[],[ ++ -L$READLINE_DIR/$PHP_LIBDIR $PHP_READLINE_LIBS ++ ]) ++ + AC_DEFINE(HAVE_LIBEDIT, 1, [ ]) + fi + + if test "$PHP_READLINE" != "no" || test "$PHP_LIBEDIT" != "no"; then +- AC_CHECK_FUNCS([rl_completion_matches]) + PHP_NEW_EXTENSION(readline, readline.c readline_cli.c, $ext_shared, cli) + PHP_SUBST(READLINE_SHARED_LIBADD) + fi +diff --git a/ext/fileinfo/libmagic/cdf.c b/ext/fileinfo/libmagic/cdf.c +index 28084fb..01af1e4 100644 +--- a/ext/fileinfo/libmagic/cdf.c ++++ b/ext/fileinfo/libmagic/cdf.c +@@ -872,8 +872,9 @@ + i, inp[i].pi_id, inp[i].pi_type, q - p, offs)); + if (inp[i].pi_type & CDF_VECTOR) { + nelements = CDF_GETUINT32(q, 1); +- if (nelements == 0) { +- DPRINTF(("CDF_VECTOR with nelements == 0\n")); ++ if (nelements > CDF_ELEMENT_LIMIT || nelements == 0) { ++ DPRINTF(("CDF_VECTOR with nelements == %" ++ SIZE_T_FORMAT "u\n", nelements)); + goto out; + } + o = 2; +@@ -948,8 +949,6 @@ + *info = inp; + inp = *info + nelem; + } +- DPRINTF(("nelements = %" SIZE_T_FORMAT "u\n", +- nelements)); + for (j = 0; j < nelements && i < sh.sh_properties; + j++, i++) + { +diff --git a/ext/fileinfo/libmagic/cdf.h b/ext/fileinfo/libmagic/cdf.h +index 9006a68..6ad5bce 100644 +--- a/ext/fileinfo/libmagic/cdf.h ++++ b/ext/fileinfo/libmagic/cdf.h +@@ -50,6 +50,7 @@ + typedef int32_t cdf_secid_t; + + #define CDF_LOOP_LIMIT 10000 ++#define CDF_ELEMENT_LIMIT 100000 + + #define CDF_SECID_NULL 0 + #define CDF_SECID_FREE -1 +diff --git a/ext/standard/string.c b/ext/standard/string.c +index 922d4fc..c88135d 100644 +--- a/ext/standard/string.c ++++ b/ext/standard/string.c +@@ -4781,7 +4781,7 @@ + if (state == 4) { + /* Inside <!-- comment --> */ + break; +- } else if (state == 2 && *(p-1) != '\\') { ++ } else if (state == 2 && p >= buf + 1 && *(p-1) != '\\') { + if (lc == c) { + lc = '\0'; + } else if (lc != '\\') { +@@ -4808,7 +4808,7 @@ + + case '!': + /* JavaScript & Other HTML scripting languages */ +- if (state == 1 && *(p-1) == '<') { ++ if (state == 1 && p >= buf + 1 && *(p-1) == '<') { + state = 3; + lc = c; + } else { +@@ -4835,7 +4835,7 @@ + + case '?': + +- if (state == 1 && *(p-1) == '<') { ++ if (state == 1 && p >= buf + 1 && *(p-1) == '<') { + br=0; + state=2; + break; +--- /dev/null ++++ b/ext/standard/tests/file/bug79099.phpt +@@ -0,0 +1,32 @@ ++--TEST-- ++Bug #79099 (OOB read in php_strip_tags_ex) ++--FILE-- ++<?php ++$stream = fopen('php://memory', 'w+'); ++fputs($stream, "<?\n\"\n"); ++rewind($stream); ++var_dump(fgetss($stream)); ++var_dump(fgetss($stream)); ++fclose($stream); ++ ++$stream = fopen('php://memory', 'w+'); ++fputs($stream, "<\0\n!\n"); ++rewind($stream); ++var_dump(fgetss($stream)); ++var_dump(fgetss($stream)); ++fclose($stream); ++ ++$stream = fopen('php://memory', 'w+'); ++fputs($stream, "<\0\n?\n"); ++rewind($stream); ++var_dump(fgetss($stream)); ++var_dump(fgetss($stream)); ++fclose($stream); ++?> ++--EXPECT-- ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" +diff --git a/ext/mbstring/libmbfl/filters/mbfilter_big5.c b/ext/mbstring/libmbfl/filters/mbfilter_big5.c +index f5ab880..5e1ca81 100644 +--- a/ext/mbstring/libmbfl/filters/mbfilter_big5.c ++++ b/ext/mbstring/libmbfl/filters/mbfilter_big5.c +@@ -138,6 +138,17 @@ + {0xf70f,0xf848,0xc740,0xc8fe}, + }; + ++static inline int is_in_cp950_pua(int c1, int c) { ++ if ((c1 >= 0xfa && c1 <= 0xfe) || (c1 >= 0x8e && c1 <= 0xa0) || ++ (c1 >= 0x81 && c1 <= 0x8d) || (c1 >= 0xc7 && c1 <= 0xc8)) { ++ return (c >=0x40 && c <= 0x7e) || (c >= 0xa1 && c <= 0xfe); ++ } ++ if (c1 == 0xc6) { ++ return c >= 0xa1 && c <= 0xfe; ++ } ++ return 0; ++} ++ + /* + * Big5 => wchar + */ +@@ -186,11 +197,7 @@ + + if (filter->from->no_encoding == mbfl_no_encoding_cp950) { + /* PUA for CP950 */ +- if (w <= 0 && +- (((c1 >= 0xfa && c1 <= 0xfe) || (c1 >= 0x8e && c1 <= 0xa0) || +- (c1 >= 0x81 && c1 <= 0x8d) ||(c1 >= 0xc7 && c1 <= 0xc8)) +- && ((c > 0x39 && c < 0x7f) || (c > 0xa0 && c < 0xff))) || +- ((c1 == 0xc6) && (c > 0xa0 && c < 0xff))) { ++ if (w <= 0 && is_in_cp950_pua(c1, c)) { + c2 = c1 << 8 | c; + for (k = 0; k < sizeof(cp950_pua_tbl)/(sizeof(unsigned short)*4); k++) { + if (c2 >= cp950_pua_tbl[k][2] && c2 <= cp950_pua_tbl[k][3]) { +--- /dev/null ++++ b/ext/mbstring/tests/bug79037.phpt +@@ -0,0 +1,10 @@ ++--TEST-- ++Bug #79037: global buffer-overflow in `mbfl_filt_conv_big5_wchar` ++--FILE-- ++<?php ++ ++var_dump(mb_convert_encoding("\x81\x3a", "UTF-8", "CP950")); ++ ++?> ++--EXPECT-- ++string(1) "?" +diff --git a/ext/standard/string.c b/ext/standard/string.c +index c88135d..018e919 100644 +--- a/ext/standard/string.c ++++ b/ext/standard/string.c +@@ -4731,7 +4731,7 @@ + switch (state) { + case 1: /* HTML/XML */ + lc = '>'; +- if (is_xml && *(p -1) == '-') { ++ if (is_xml && p >= buf + 1 && *(p-1) == '-') { + break; + } + in_q = state = is_xml = 0; +@@ -4752,7 +4752,7 @@ + break; + + case 2: /* PHP */ +- if (!br && lc != '\"' && *(p-1) == '?') { ++ if (!br && lc != '\"' && p >= buf + 1 && *(p-1) == '?') { + in_q = state = 0; + tp = tbuf; + } +diff --git a/ext/session/session.c b/ext/session/session.c +index bf8797a..d3226ee 100644 +--- a/ext/session/session.c ++++ b/ext/session/session.c +@@ -2999,9 +2999,11 @@ + if (PS(rfc1867_cleanup)) { + php_session_rfc1867_cleanup(progress); + } else { +- add_assoc_bool_ex(&progress->data, "done", sizeof("done") - 1, 1); +- Z_LVAL_P(progress->post_bytes_processed) = data->post_bytes_processed; +- php_session_rfc1867_update(progress, 1); ++ if (!Z_ISUNDEF(progress->data)) { ++ add_assoc_bool_ex(&progress->data, "done", sizeof("done") - 1, 1); ++ Z_LVAL_P(progress->post_bytes_processed) = data->post_bytes_processed; ++ php_session_rfc1867_update(progress, 1); ++ } + } + php_rshutdown_session_globals(); + } +--- /dev/null ++++ b/ext/session/tests/bug79221.phpt +@@ -0,0 +1,45 @@ ++--TEST-- ++Null Pointer Dereference in PHP Session Upload Progress ++--INI-- ++error_reporting=0 ++file_uploads=1 ++upload_max_filesize=1024 ++session.save_path= ++session.name=PHPSESSID ++session.serialize_handler=php ++session.use_strict_mode=0 ++session.use_cookies=1 ++session.use_only_cookies=0 ++session.upload_progress.enabled=1 ++session.upload_progress.cleanup=0 ++session.upload_progress.prefix=upload_progress_ ++session.upload_progress.name=PHP_SESSION_UPLOAD_PROGRESS ++session.upload_progress.freq=1% ++session.upload_progress.min_freq=0.000000001 ++--COOKIE-- ++PHPSESSID=session-upload ++--POST_RAW-- ++Content-Type: multipart/form-data; boundary=---------------------------20896060251896012921717172737 ++-----------------------------20896060251896012921717172737 ++Content-Disposition: form-data; name="PHPSESSID" ++ ++session-upload ++-----------------------------20896060251896012921717172737 ++Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS" ++ ++ryat ++-----------------------------20896060251896012921717172737 ++Content-Disposition: form-data; file="file"; ryat="filename" ++ ++1 ++-----------------------------20896060251896012921717172737-- ++--FILE-- ++<?php ++ ++session_start(); ++var_dump($_SESSION); ++session_destroy(); ++ ++--EXPECTF-- ++array(0) { ++} +diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c +index c1ba97a..b22a6ac 100644 +--- a/ext/phar/phar_object.c ++++ b/ext/phar/phar_object.c +@@ -1439,6 +1439,7 @@ + char *str_key; + zend_class_entry *ce = p_obj->c; + phar_archive_object *phar_obj = p_obj->p; ++ php_stream_statbuf ssb; + + value = iter->funcs->get_current_data(iter); + +@@ -1718,6 +1719,16 @@ + php_stream_copy_to_stream_ex(fp, p_obj->fp, PHP_STREAM_COPY_ALL, &contents_len); + data->internal_file->uncompressed_filesize = data->internal_file->compressed_filesize = + php_stream_tell(p_obj->fp) - data->internal_file->offset; ++ if (php_stream_stat(fp, &ssb) != -1) { ++ data->internal_file->flags = ssb.sb.st_mode & PHAR_ENT_PERM_MASK ; ++ } else { ++#ifndef _WIN32 ++ mode_t mask; ++ mask = umask(0); ++ umask(mask); ++ data->internal_file->flags &= ~mask; ++#endif ++ } + } + + if (close_fp) { +--- /dev/null ++++ b/ext/phar/tests/bug79082.phpt +@@ -0,0 +1,52 @@ ++--TEST-- ++Phar: Bug #79082: Files added to tar with Phar::buildFromIterator have all-access permissions ++--SKIPIF-- ++<?php ++if (!extension_loaded("phar")) die("skip"); ++if (defined("PHP_WINDOWS_VERSION_MAJOR")) die("skip not for Windows") ++?> ++--FILE-- ++<?php ++umask(022); ++var_dump(decoct(umask())); ++chmod(__DIR__ . '/test79082/test79082-testfile', 0644); ++chmod(__DIR__ . '/test79082/test79082-testfile2', 0400); ++ ++foreach([Phar::TAR => 'tar', Phar::ZIP => 'zip'] as $mode => $ext) { ++ clearstatcache(); ++ $phar = new PharData(__DIR__ . '/test79082.' . $ext, null, null, $mode); ++ $phar->buildFromIterator(new \RecursiveDirectoryIterator(__DIR__ . '/test79082', \FilesystemIterator::SKIP_DOTS), __DIR__ . '/test79082'); ++ $phar->extractTo(__DIR__); ++ var_dump(decoct(stat(__DIR__ . '/test79082-testfile')['mode'])); ++ var_dump(decoct(stat(__DIR__ . '/test79082-testfile2')['mode'])); ++ unlink(__DIR__ . '/test79082-testfile'); ++ unlink(__DIR__ . '/test79082-testfile2'); ++} ++foreach([Phar::TAR => 'tar', Phar::ZIP => 'zip'] as $mode => $ext) { ++ clearstatcache(); ++ $phar = new PharData(__DIR__ . '/test79082-d.' . $ext, null, null, $mode); ++ $phar->buildFromDirectory(__DIR__ . '/test79082'); ++ $phar->extractTo(__DIR__); ++ var_dump(decoct(stat(__DIR__ . '/test79082-testfile')['mode'])); ++ var_dump(decoct(stat(__DIR__ . '/test79082-testfile2')['mode'])); ++ unlink(__DIR__ . '/test79082-testfile'); ++ unlink(__DIR__ . '/test79082-testfile2'); ++} ++?> ++--CLEAN-- ++<? ++unlink(__DIR__ . '/test79082.tar'); ++unlink(__DIR__ . '/test79082.zip'); ++unlink(__DIR__ . '/test79082-d.tar'); ++unlink(__DIR__ . '/test79082-d.zip'); ++?> ++--EXPECT-- ++string(2) "22" ++string(6) "100644" ++string(6) "100400" ++string(6) "100644" ++string(6) "100400" ++string(6) "100644" ++string(6) "100400" ++string(6) "100644" ++string(6) "100400" +--- /dev/null ++++ b/ext/phar/tests/test79082/test79082-testfile +@@ -0,0 +1 @@ ++test +--- /dev/null ++++ b/ext/phar/tests/test79082/test79082-testfile2 +@@ -0,0 +1 @@ ++test +diff --git a/ext/exif/exif.c b/ext/exif/exif.c +index 406fee4..9130cea 100644 +--- a/ext/exif/exif.c ++++ b/ext/exif/exif.c +@@ -3243,6 +3243,11 @@ + { + unsigned exif_value_2a, offset_of_ifd; + ++ if (length < 2) { ++ exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Missing TIFF alignment marker"); ++ return; ++ } ++ + /* set the thumbnail stuff to nothing so we can test to see if they get set up */ + if (memcmp(CharBuf, "II", 2) == 0) { + ImageInfo->motorola_intel = 0; +@@ -3395,7 +3400,7 @@ + return FALSE; + } + +- sn = exif_file_sections_add(ImageInfo, marker, itemlen+1, NULL); ++ sn = exif_file_sections_add(ImageInfo, marker, itemlen, NULL); + Data = ImageInfo->file.list[sn].data; + + /* Store first two pre-read bytes. */ +--- /dev/null ++++ b/ext/exif/tests/bug79282.phpt +@@ -0,0 +1,15 @@ ++--TEST-- ++Bug #79282: Use-of-uninitialized-value in exif ++--FILE-- ++<?php ++ ++var_dump(exif_read_data('data://image/jpeg;base64,/9jhAAlFeGlmAAAg')); ++ ++?> ++--EXPECTF-- ++Warning: exif_read_data(): Invalid TIFF alignment marker in %s on line %d ++ ++Warning: exif_read_data(): File structure corrupted in %s on line %d ++ ++Warning: exif_read_data(): Invalid JPEG file in %s on line %d ++bool(false) +diff --git a/ext/standard/exec.c b/ext/standard/exec.c +index 8af1180..02d9539 100644 +--- a/ext/standard/exec.c ++++ b/ext/standard/exec.c +@@ -524,6 +524,15 @@ + return; + } + ++ if (!command_len) { ++ php_error_docref(NULL, E_WARNING, "Cannot execute a blank command"); ++ RETURN_FALSE; ++ } ++ if (strlen(command) != command_len) { ++ php_error_docref(NULL, E_WARNING, "NULL byte detected. Possible attack"); ++ RETURN_FALSE; ++ } ++ + #ifdef PHP_WIN32 + if ((in=VCWD_POPEN(command, "rt"))==NULL) { + #else +diff --git a/ext/standard/url.c b/ext/standard/url.c +index 39e5b1b..4cc1f77 100644 +--- a/ext/standard/url.c ++++ b/ext/standard/url.c +@@ -540,7 +540,7 @@ + #ifndef CHARSET_EBCDIC + *dest = (char) php_htoi(data + 1); + #else +- *dest = os_toebcdic[(char) php_htoi(data + 1)]; ++ *dest = os_toebcdic[(unsigned char) php_htoi(data + 1)]; + #endif + data += 2; + len -= 2; +@@ -632,7 +632,7 @@ + #ifndef CHARSET_EBCDIC + *dest = (char) php_htoi(data + 1); + #else +- *dest = os_toebcdic[(char) php_htoi(data + 1)]; ++ *dest = os_toebcdic[(unsigned char) php_htoi(data + 1)]; + #endif + data += 2; + len -= 2; +diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c +index cdf77f2..8f0c5db 100644 +--- a/ext/zip/php_zip.c ++++ b/ext/zip/php_zip.c +@@ -1454,6 +1454,21 @@ + ze_obj->filename = NULL; + } + ++#if LIBZIP_VERSION_MAJOR > 1 || LIBZIP_VERSION_MAJOR == 1 && LIBZIP_VERSION_MINOR >= 6 ++ /* reduce BC break introduce in libzip 1.6.0 ++ "Do not accept empty files as valid zip archives any longer" */ ++ ++ /* open for write without option to empty the archive */ ++ if ((flags & (ZIP_TRUNCATE | ZIP_RDONLY)) == 0) { ++ zend_stat_t st; ++ ++ /* exists and is empty */ ++ if (VCWD_STAT(resolved_path, &st) == 0 && st.st_size == 0) { ++ flags |= ZIP_TRUNCATE; ++ } ++ } ++#endif ++ + intern = zip_open(resolved_path, flags, &err); + if (!intern || err) { + efree(resolved_path); +diff --git a/main/rfc1867.c b/main/rfc1867.c +index b930e07..14ffbea 100644 +--- a/main/rfc1867.c ++++ b/main/rfc1867.c +@@ -692,7 +692,8 @@ + char *boundary, *s = NULL, *boundary_end = NULL, *start_arr = NULL, *array_index = NULL; + char *lbuf = NULL, *abuf = NULL; + zend_string *temp_filename = NULL; +- int boundary_len = 0, cancel_upload = 0, is_arr_upload = 0, array_len = 0; ++ int boundary_len = 0, cancel_upload = 0, is_arr_upload = 0; ++ size_t array_len = 0; + int64_t total_bytes = 0, max_file_size = 0; + int skip_upload = 0, anonindex = 0, is_anonymous; + HashTable *uploaded_files = NULL; +@@ -1126,7 +1127,7 @@ + is_arr_upload = (start_arr = strchr(param,'[')) && (param[strlen(param)-1] == ']'); + + if (is_arr_upload) { +- array_len = (int)strlen(start_arr); ++ array_len = strlen(start_arr); + if (array_index) { + efree(array_index); + } +diff --git a/main/rfc1867.c b/main/rfc1867.c +index 14ffbea..1742b9c 100644 +--- a/main/rfc1867.c ++++ b/main/rfc1867.c +@@ -616,7 +616,7 @@ + } + + /* read until a boundary condition */ +-static int multipart_buffer_read(multipart_buffer *self, char *buf, size_t bytes, int *end) ++static size_t multipart_buffer_read(multipart_buffer *self, char *buf, size_t bytes, int *end) + { + size_t len, max; + char *bound; +@@ -655,7 +655,7 @@ + self->buf_begin += len; + } + +- return (int)len; ++ return len; + } + + /* +@@ -665,7 +665,7 @@ + static char *multipart_buffer_read_body(multipart_buffer *self, size_t *len) + { + char buf[FILLUNIT], *out=NULL; +- int total_bytes=0, read_bytes=0; ++ size_t total_bytes=0, read_bytes=0; + + while((read_bytes = multipart_buffer_read(self, buf, sizeof(buf), NULL))) { + out = erealloc(out, total_bytes + read_bytes + 1); +diff --git a/NEWS b/NEWS +index 15bf59b..74fbea5 100644 +--- a/NEWS ++++ b/NEWS +@@ -3,6 +3,10 @@ + + Backported from 7.2.33 + ++- Core: ++ . Fixed bug #79877 (getimagesize function silently truncates after a null ++ byte) (cmb) ++ + - Phar: + . Fixed bug #79797 (Use of freed hash key in the phar_parse_zipfile + function). (CVE-2020-7068) (cmb) +diff --git a/ext/standard/image.c b/ext/standard/image.c +index 1d999ca..a5a86c2 100644 +--- a/ext/standard/image.c ++++ b/ext/standard/image.c +@@ -1474,6 +1474,11 @@ + return; + } + ++ if (mode == FROM_PATH && CHECK_NULL_PATH(input, input_len)) { ++ php_error_docref(NULL, E_WARNING, "Invalid path"); ++ return; ++ } ++ + if (argc == 2) { + zval_dtor(info); + array_init(info); +--- /dev/null ++++ b/ext/standard/tests/image/bug79877.phpt +@@ -0,0 +1,9 @@ ++--TEST-- ++Bug #79877 (getimagesize function silently truncates after a null byte) ++--FILE-- ++<?php ++var_dump(getimagesize("/tmp/a.png\0xx")); ++?> ++--EXPECTF-- ++Warning: getimagesize(): Invalid path in %s on line %d ++NULL +diff --git a/main/php_variables.c b/main/php_variables.c +index c56d230..d0223df 100644 +--- a/main/php_variables.c ++++ b/main/php_variables.c +@@ -484,7 +484,9 @@ + size_t new_val_len; + + *val++ = '\0'; +- php_url_decode(var, strlen(var)); ++ if (arg != PARSE_COOKIE) { ++ php_url_decode(var, strlen(var)); ++ } + val_len = php_url_decode(val, strlen(val)); + val = estrndup(val, val_len); + if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len)) { +@@ -495,7 +497,9 @@ + size_t val_len; + size_t new_val_len; + +- php_url_decode(var, strlen(var)); ++ if (arg != PARSE_COOKIE) { ++ php_url_decode(var, strlen(var)); ++ } + val_len = 0; + val = estrndup("", val_len); + if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len)) { +diff --git a/tests/basic/022.phpt b/tests/basic/022.phpt +index 0ab70d4..bd1db13 100644 +--- a/tests/basic/022.phpt ++++ b/tests/basic/022.phpt +@@ -10,7 +10,7 @@ + var_dump($_COOKIE); + ?> + --EXPECT-- +-array(10) { ++array(12) { + ["cookie1"]=> + string(6) "val1 " + ["cookie2"]=> +@@ -19,11 +19,15 @@ + string(6) "val 3." + ["cookie_4"]=> + string(10) " value 4 ;" ++ ["%20cookie1"]=> ++ string(6) "ignore" ++ ["+cookie1"]=> ++ string(6) "ignore" + ["cookie__5"]=> + string(7) " value" +- ["cookie_6"]=> ++ ["cookie%206"]=> + string(3) "þæö" +- ["cookie_7"]=> ++ ["cookie+7"]=> + string(0) "" + ["$cookie_8"]=> + string(0) "" +diff --git a/tests/basic/023.phpt b/tests/basic/023.phpt +index ca5f1dc..0e2e0ac 100644 +--- a/tests/basic/023.phpt ++++ b/tests/basic/023.phpt +@@ -10,9 +10,11 @@ + var_dump($_COOKIE); + ?> + --EXPECT-- +-array(3) { ++array(4) { + ["c_o_o_k_i_e"]=> + string(5) "value" ++ ["c%20o+o_k+i%20e"]=> ++ string(1) "v" + ["name"]=> + string(24) ""value","value",UEhQIQ==" + ["UEhQIQ"]=> +--- /dev/null ++++ b/tests/basic/bug79699.phpt +@@ -0,0 +1,22 @@ ++--TEST-- ++Cookies Security Bug ++--INI-- ++max_input_vars=1000 ++filter.default=unsafe_raw ++--COOKIE-- ++__%48ost-evil=evil; __Host-evil=good; %66oo=baz;foo=bar ++--FILE-- ++<?php ++var_dump($_COOKIE); ++?> ++--EXPECT-- ++array(4) { ++ ["__%48ost-evil"]=> ++ string(4) "evil" ++ ["__Host-evil"]=> ++ string(4) "good" ++ ["%66oo"]=> ++ string(3) "baz" ++ ["foo"]=> ++ string(3) "bar" ++} +diff --git a/ext/standard/tests/strings/url_t.phpt b/ext/standard/tests/strings/url_t.phpt +index 79ff3bc..f564f59 100644 +--- a/ext/standard/tests/strings/url_t.phpt ++++ b/ext/standard/tests/strings/url_t.phpt +@@ -575,15 +575,13 @@ + string(16) "some_page_ref123" + } + +---> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(7) { ++--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(6) { + ["scheme"]=> + string(4) "http" + ["host"]=> +- string(11) "www.php.net" ++ string(26) "secret@hideout@www.php.net" + ["port"]=> + int(80) +- ["user"]=> +- string(14) "secret@hideout" + ["path"]=> + string(10) "/index.php" + ["query"]=> +--- /dev/null ++++ b/ext/standard/tests/url/bug77423.phpt +@@ -0,0 +1,30 @@ ++--TEST-- ++Bug #77423 (parse_url() will deliver a wrong host to user) ++--FILE-- ++<?php ++$urls = array( ++ "http://php.net\@aliyun.com/aaa.do", ++ "https://example.com\uFF03@bing.com", ++); ++foreach ($urls as $url) { ++ var_dump(filter_var($url, FILTER_VALIDATE_URL)); ++ var_dump(parse_url($url)); ++} ++?> ++--EXPECT-- ++bool(false) ++array(3) { ++ ["scheme"]=> ++ string(4) "http" ++ ["host"]=> ++ string(19) "php.net\@aliyun.com" ++ ["path"]=> ++ string(7) "/aaa.do" ++} ++bool(false) ++array(2) { ++ ["scheme"]=> ++ string(5) "https" ++ ["host"]=> ++ string(26) "example.com\uFF03@bing.com" ++} +diff --git a/ext/standard/tests/url/parse_url_basic_001.phpt b/ext/standard/tests/url/parse_url_basic_001.phpt +index 4606849..5101099 100644 +--- a/ext/standard/tests/url/parse_url_basic_001.phpt ++++ b/ext/standard/tests/url/parse_url_basic_001.phpt +@@ -506,15 +506,13 @@ + string(16) "some_page_ref123" + } + +---> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(7) { ++--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(6) { + ["scheme"]=> + string(4) "http" + ["host"]=> +- string(11) "www.php.net" ++ string(26) "secret@hideout@www.php.net" + ["port"]=> + int(80) +- ["user"]=> +- string(14) "secret@hideout" + ["path"]=> + string(10) "/index.php" + ["query"]=> +diff --git a/ext/standard/tests/url/parse_url_basic_003.phpt b/ext/standard/tests/url/parse_url_basic_003.phpt +index 3d5a4a3..7968fd3 100644 +--- a/ext/standard/tests/url/parse_url_basic_003.phpt ++++ b/ext/standard/tests/url/parse_url_basic_003.phpt +@@ -68,7 +68,7 @@ + --> http://secret:@www.php.net/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(11) "www.php.net" + --> http://:hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(11) "www.php.net" + --> http://secret:hideout@www.php.net/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(11) "www.php.net" +---> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(11) "www.php.net" ++--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(26) "secret@hideout@www.php.net" + --> http://secret:hid:out@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(11) "www.php.net" + --> nntp://news.php.net : string(12) "news.php.net" + --> ftp://ftp.gnu.org/gnu/glic/glibc.tar.gz : string(11) "ftp.gnu.org" +diff --git a/ext/standard/tests/url/parse_url_basic_005.phpt b/ext/standard/tests/url/parse_url_basic_005.phpt +index aefb339..ba778bf 100644 +--- a/ext/standard/tests/url/parse_url_basic_005.phpt ++++ b/ext/standard/tests/url/parse_url_basic_005.phpt +@@ -68,7 +68,7 @@ + --> http://secret:@www.php.net/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(6) "secret" + --> http://:hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(0) "" + --> http://secret:hideout@www.php.net/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(6) "secret" +---> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(14) "secret@hideout" ++--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : NULL + --> http://secret:hid:out@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123 : string(6) "secret" + --> nntp://news.php.net : NULL + --> ftp://ftp.gnu.org/gnu/glic/glibc.tar.gz : NULL +diff --git a/ext/standard/url.c b/ext/standard/url.c +index 4cc1f77..d56dc24 100644 +--- a/ext/standard/url.c ++++ b/ext/standard/url.c +@@ -92,6 +92,22 @@ + return php_url_parse_ex(str, strlen(str)); + } + ++static int is_userinfo_valid(const char *str, size_t len) ++{ ++ char *valid = "-._~!$&'()*+,;=:"; ++ char *p = str; ++ while (p - str < len) { ++ if (isalpha(*p) || isdigit(*p) || strchr(valid, *p)) { ++ p++; ++ } else if (*p == '%' && p - str <= len - 3 && isdigit(*(p+1)) && isxdigit(*(p+2))) { ++ p += 3; ++ } else { ++ return 0; ++ } ++ } ++ return 1; ++} ++ + /* {{{ php_url_parse + */ + PHPAPI php_url *php_url_parse_ex(char const *str, size_t length) +@@ -235,13 +251,18 @@ + ret->pass = estrndup(pp, (p-pp)); + php_replace_controlchars_ex(ret->pass, (p-pp)); + } else { ++ if (!is_userinfo_valid(s, p-s)) { ++ goto check_port; ++ } + ret->user = estrndup(s, (p-s)); + php_replace_controlchars_ex(ret->user, (p-s)); ++ + } + + s = p + 1; + } + ++check_port: + /* check for port */ + if (s < ue && *s == '[' && *(e-1) == ']') { + /* Short circuit portscan, +diff --git a/ext/imap/php_imap.c b/ext/imap/php_imap.c +index 6ce4b78..7de074a 100644 +--- a/ext/imap/php_imap.c ++++ b/ext/imap/php_imap.c +@@ -3531,6 +3531,23 @@ + } + /* }}} */ + ++static zend_bool header_injection(zend_string *str, zend_bool adrlist) ++{ ++ char *p = ZSTR_VAL(str); ++ ++ while ((p = strpbrk(p, "\r\n")) != NULL) { ++ if (!(p[0] == '\r' && p[1] == '\n') ++ /* adrlists do not support folding, but swallow trailing line breaks */ ++ && !((adrlist && p[1] == '\0') ++ /* other headers support folding */ ++ || !adrlist && (p[1] == ' ' || p[1] == '\t'))) { ++ return 1; ++ } ++ p++; ++ } ++ return 0; ++} ++ + /* {{{ proto string imap_mail_compose(array envelope, array body) + Create a MIME message based on given envelope and body sections */ + PHP_FUNCTION(imap_mail_compose) +@@ -3551,6 +3568,13 @@ + return; + } + ++#define CHECK_HEADER_INJECTION(zstr, adrlist, header) \ ++ if (header_injection(zstr, adrlist)) { \ ++ php_error_docref(NULL, E_WARNING, "header injection attempt in " header); \ ++ RETVAL_FALSE; \ ++ goto done; \ ++ } ++ + #define PHP_RFC822_PARSE_ADRLIST(target, value) \ + str_copy = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)); \ + rfc822_parse_adrlist(target, str_copy, "NO HOST"); \ +@@ -3559,46 +3583,57 @@ + env = mail_newenvelope(); + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "remail", sizeof("remail") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "remail"); + env->remail = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "return_path", sizeof("return_path") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "return_path"); + PHP_RFC822_PARSE_ADRLIST(&env->return_path, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "date", sizeof("date") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "date"); + env->date = (unsigned char*)cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "from", sizeof("from") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "from"); + PHP_RFC822_PARSE_ADRLIST(&env->from, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "reply_to", sizeof("reply_to") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "reply_to"); + PHP_RFC822_PARSE_ADRLIST(&env->reply_to, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "in_reply_to", sizeof("in_reply_to") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "in_reply_to"); + env->in_reply_to = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "subject", sizeof("subject") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "subject"); + env->subject = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "to", sizeof("to") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "to"); + PHP_RFC822_PARSE_ADRLIST(&env->to, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "cc", sizeof("cc") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "cc"); + PHP_RFC822_PARSE_ADRLIST(&env->cc, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "bcc", sizeof("bcc") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 1, "bcc"); + PHP_RFC822_PARSE_ADRLIST(&env->bcc, pvalue); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "message_id", sizeof("message_id") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "message_id"); + env->message_id=cpystr(Z_STRVAL_P(pvalue)); + } + +@@ -3608,6 +3643,7 @@ + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pvalue), env_data) { + custom_headers_param = mail_newbody_parameter(); + convert_to_string_ex(env_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(env_data), 0, "custom_headers"); + custom_headers_param->value = (char *) fs_get(Z_STRLEN_P(env_data) + 1); + custom_headers_param->attribute = NULL; + memcpy(custom_headers_param->value, Z_STRVAL_P(env_data), Z_STRLEN_P(env_data) + 1); +@@ -3640,6 +3676,7 @@ + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body charset"); + tmp_param = mail_newbody_parameter(); + tmp_param->value = cpystr(Z_STRVAL_P(pvalue)); + tmp_param->attribute = cpystr("CHARSET"); +@@ -3650,9 +3687,11 @@ + if(Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body disposition key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body disposition value"); + disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3663,18 +3702,22 @@ + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body subtype"); + bod->subtype = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body id"); + bod->id = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body description"); + bod->description = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body disposition.type"); + bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1); + memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1); + } +@@ -3682,9 +3725,11 @@ + if (Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body type.parameters key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body type.parameters value"); + disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3713,6 +3758,7 @@ + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body md5"); + bod->md5 = cpystr(Z_STRVAL_P(pvalue)); + } + } else if (Z_TYPE_P(data) == IS_ARRAY) { +@@ -3743,6 +3789,7 @@ + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body charset"); + tmp_param = mail_newbody_parameter(); + tmp_param->value = (char *) fs_get(Z_STRLEN_P(pvalue) + 1); + memcpy(tmp_param->value, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue) + 1); +@@ -3754,9 +3801,11 @@ + if (Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body type.parameters key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body type.parameters value"); + disp_param->value = (char *)fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3767,18 +3816,22 @@ + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body subtype"); + bod->subtype = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body id"); + bod->id = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body description"); + bod->description = cpystr(Z_STRVAL_P(pvalue)); + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body disposition.type"); + bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1); + memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1); + } +@@ -3786,9 +3839,11 @@ + if (Z_TYPE_P(pvalue) == IS_ARRAY) { + disp_param = tmp_param = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) { ++ CHECK_HEADER_INJECTION(key, 0, "body disposition key"); + disp_param = mail_newbody_parameter(); + disp_param->attribute = cpystr(ZSTR_VAL(key)); + convert_to_string_ex(disp_data); ++ CHECK_HEADER_INJECTION(Z_STR_P(disp_data), 0, "body disposition value"); + disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1); + memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1); + disp_param->next = tmp_param; +@@ -3817,6 +3872,7 @@ + } + if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) { + convert_to_string_ex(pvalue); ++ CHECK_HEADER_INJECTION(Z_STR_P(pvalue), 0, "body md5"); + bod->md5 = cpystr(Z_STRVAL_P(pvalue)); + } + } +--- /dev/null ++++ b/ext/imap/tests/bug80710_1.phpt +@@ -0,0 +1,37 @@ ++--TEST-- ++Bug #80710 (imap_mail_compose() header injection) - MIME Splitting Attack ++--SKIPIF-- ++<?php ++if (!extension_loaded("imap")) die("skip imap extension not available"); ++?> ++--FILE-- ++<?php ++$envelope["from"]= "joe@example.com\n From : X-INJECTED"; ++$envelope["to"] = "foo@example.com\nFrom: X-INJECTED"; ++$envelope["cc"] = "bar@example.com\nFrom: X-INJECTED"; ++$envelope["subject"] = "bar@example.com\n\n From : X-INJECTED"; ++$envelope["x-remail"] = "bar@example.com\nFrom: X-INJECTED"; ++$envelope["something"] = "bar@example.com\nFrom: X-INJECTED"; ++ ++$part1["type"] = TYPEMULTIPART; ++$part1["subtype"] = "mixed"; ++ ++$part2["type"] = TYPEAPPLICATION; ++$part2["encoding"] = ENCBINARY; ++$part2["subtype"] = "octet-stream\nContent-Type: X-INJECTED"; ++$part2["description"] = "some file\nContent-Type: X-INJECTED"; ++$part2["contents.data"] = "ABC\nContent-Type: X-INJECTED"; ++ ++$part3["type"] = TYPETEXT; ++$part3["subtype"] = "plain"; ++$part3["description"] = "description3"; ++$part3["contents.data"] = "contents.data3\n\n\n\t"; ++ ++$body[1] = $part1; ++$body[2] = $part2; ++$body[3] = $part3; ++ ++echo imap_mail_compose($envelope, $body); ++?> ++--EXPECTF-- ++Warning: imap_mail_compose(): header injection attempt in from in %s on line %d +--- /dev/null ++++ b/ext/imap/tests/bug80710_2.phpt +@@ -0,0 +1,37 @@ ++--TEST-- ++Bug #80710 (imap_mail_compose() header injection) - Remail ++--SKIPIF-- ++<?php ++if (!extension_loaded("imap")) die("skip imap extension not available"); ++?> ++--FILE-- ++<?php ++$envelope["from"]= "joe@example.com\n From : X-INJECTED"; ++$envelope["to"] = "foo@example.com\nFrom: X-INJECTED"; ++$envelope["cc"] = "bar@example.com\nFrom: X-INJECTED"; ++$envelope["subject"] = "bar@example.com\n\n From : X-INJECTED"; ++$envelope["remail"] = "X-INJECTED-REMAIL: X-INJECTED\nFrom: X-INJECTED-REMAIL-FROM"; //<--- Injected as first hdr ++$envelope["something"] = "bar@example.com\nFrom: X-INJECTED"; ++ ++$part1["type"] = TYPEMULTIPART; ++$part1["subtype"] = "mixed"; ++ ++$part2["type"] = TYPEAPPLICATION; ++$part2["encoding"] = ENCBINARY; ++$part2["subtype"] = "octet-stream\nContent-Type: X-INJECTED"; ++$part2["description"] = "some file\nContent-Type: X-INJECTED"; ++$part2["contents.data"] = "ABC\nContent-Type: X-INJECTED"; ++ ++$part3["type"] = TYPETEXT; ++$part3["subtype"] = "plain"; ++$part3["description"] = "description3"; ++$part3["contents.data"] = "contents.data3\n\n\n\t"; ++ ++$body[1] = $part1; ++$body[2] = $part2; ++$body[3] = $part3; ++ ++echo imap_mail_compose($envelope, $body); ++?> ++--EXPECTF-- ++Warning: imap_mail_compose(): header injection attempt in remail in %s on line %d +diff --git a/ext/pdo_firebird/firebird_statement.c b/ext/pdo_firebird/firebird_statement.c +index c5e6b68..bdde6c7 100644 +--- a/ext/pdo_firebird/firebird_statement.c ++++ b/ext/pdo_firebird/firebird_statement.c +@@ -133,8 +133,14 @@ + } + if (result[0] == isc_info_sql_records) { + unsigned i = 3, result_size = isc_vax_integer(&result[1], 2); ++ if (result_size > sizeof(result)) { ++ goto error; ++ } + while (result[i] != isc_info_end && i < result_size) { + short len = (short) isc_vax_integer(&result[i + 1], 2); ++ if (len != 1 && len != 2 && len != 4) { ++ goto error; ++ } + if (result[i] != isc_info_req_select_count) { + affected_rows += isc_vax_integer(&result[i + 3], len); + } +@@ -158,6 +164,7 @@ + return 1; + } while (0); + ++error: + RECORD_ERROR(stmt); + + return 0; +--- /dev/null ++++ b/ext/pdo_firebird/tests/bug_76450.data +@@ -0,0 +1 @@ ++ +\ No newline at end of file +--- /dev/null ++++ b/ext/pdo_firebird/tests/bug_76450.phpt +@@ -0,0 +1,29 @@ ++--TEST-- ++Bug #76450 (SIGSEGV in firebird_stmt_execute) ++--SKIPIF-- ++<?php ++if (!extension_loaded('pdo_firebird')) die("skip pdo_firebird extension not available"); ++if (!extension_loaded('sockets')) die("skip sockets extension not available"); ++?> ++--FILE-- ++<?php ++require_once "payload_server.inc"; ++ ++$address = run_server(__DIR__ . "/bug_76450.data"); ++ ++// no need to change the credentials; we're running against a fake server ++$dsn = "firebird:dbname=inet://$address/test"; ++$username = 'SYSDBA'; ++$password = 'masterkey'; ++ ++$dbh = new PDO($dsn, $username, $password, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]); ++$sql = "EXECUTE PROCEDURE test_proc 123"; ++$query = $dbh->prepare($sql); ++try { ++ $query->execute(); ++} catch (Exception $ex) { ++ echo "{$ex->getMessage()}\n"; ++} ++?> ++--EXPECT-- ++SQLSTATE[HY000]: General error +diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c +index 446f52d..0fc1c95 100644 +--- a/ext/pdo_firebird/firebird_driver.c ++++ b/ext/pdo_firebird/firebird_driver.c +@@ -252,8 +252,17 @@ + if (result[0] == isc_info_sql_records) { + unsigned i = 3, result_size = isc_vax_integer(&result[1],2); + ++ if (result_size > sizeof(result)) { ++ ret = -1; ++ goto free_statement; ++ } + while (result[i] != isc_info_end && i < result_size) { + short len = (short)isc_vax_integer(&result[i+1],2); ++ /* bail out on bad len */ ++ if (len != 1 && len != 2 && len != 4) { ++ ret = -1; ++ goto free_statement; ++ } + if (result[i] != isc_info_req_select_count) { + ret += isc_vax_integer(&result[i+3],len); + } +--- /dev/null ++++ b/ext/pdo_firebird/tests/bug_76449.data +@@ -0,0 +1 @@ ++ +\ No newline at end of file +--- /dev/null ++++ b/ext/pdo_firebird/tests/bug_76449.phpt +@@ -0,0 +1,23 @@ ++--TEST-- ++Bug #76449 (SIGSEGV in firebird_handle_doer) ++--SKIPIF-- ++<?php ++if (!extension_loaded('pdo_firebird')) die("skip pdo_firebird extension not available"); ++if (!extension_loaded('sockets')) die("skip sockets extension not available"); ++?> ++--FILE-- ++<?php ++require_once "payload_server.inc"; ++ ++$address = run_server(__DIR__ . "/bug_76449.data"); ++ ++// no need to change the credentials; we're running against a fake server ++$dsn = "firebird:dbname=inet://$address/test"; ++$username = 'SYSDBA'; ++$password = 'masterkey'; ++ ++$dbh = new PDO($dsn, $username, $password, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]); ++var_dump($dbh->exec("INSERT INTO test VALUES ('hihi2', 'xxxxx')")); ++?> ++--EXPECT-- ++bool(false) +diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c +index 0fc1c95..f555511 100644 +--- a/ext/pdo_firebird/firebird_driver.c ++++ b/ext/pdo_firebird/firebird_driver.c +@@ -555,14 +555,16 @@ + } + /* }}} */ + ++#define INFO_BUF_LEN 512 ++ + /* callback to used to report database server info */ + static void firebird_info_cb(void *arg, char const *s) /* {{{ */ + { + if (arg) { + if (*(char*)arg) { /* second call */ +- strcat(arg, " "); ++ strlcat(arg, " ", INFO_BUF_LEN); + } +- strcat(arg, s); ++ strlcat(arg, s, INFO_BUF_LEN); + } + } + /* }}} */ +@@ -573,7 +575,7 @@ + pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data; + + switch (attr) { +- char tmp[512]; ++ char tmp[INFO_BUF_LEN]; + + case PDO_ATTR_AUTOCOMMIT: + ZVAL_LONG(val,dbh->auto_commit); +--- /dev/null ++++ b/ext/pdo_firebird/tests/bug_76448.data +@@ -0,0 +1 @@ ++ +\ No newline at end of file +--- /dev/null ++++ b/ext/pdo_firebird/tests/bug_76448.phpt +@@ -0,0 +1,23 @@ ++--TEST-- ++Bug #76448 (Stack buffer overflow in firebird_info_cb) ++--SKIPIF-- ++<?php ++if (!extension_loaded('pdo_firebird')) die("skip podo_firebird extension not available"); ++if (!extension_loaded('sockets')) die("skip sockets extension not available"); ++?> ++--FILE-- ++<?php ++require_once "payload_server.inc"; ++ ++$address = run_server(__DIR__ . "/bug_76448.data"); ++ ++// no need to change the credentials; we're running against a falke server ++$dsn = "firebird:dbname=inet://$address/test"; ++$username = 'SYSDBA'; ++$password = 'masterkey'; ++ ++$dbh = new PDO($dsn, $username, $password, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]); ++var_dump($dbh->getAttribute(PDO::ATTR_SERVER_INFO)); ++?> ++--EXPECT-- ++bool(false) +diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c +index 8f0c5db..72827ac 100644 +--- a/ext/zip/php_zip.c ++++ b/ext/zip/php_zip.c +@@ -101,8 +101,8 @@ + return NULL; + } + +- if (IS_SLASH(path[0])) { +- return path + 1; ++ if (IS_ABSOLUTE_PATH(path, path_len)) { ++ return path + COPY_WHEN_ABSOLUTE(path) + 1; + } + + i = path_len; +--- /dev/null ++++ b/ext/zip/tests/bug81420.phpt +@@ -0,0 +1,24 @@ ++--TEST-- ++Bug #81420 (ZipArchive::extractTo extracts outside of destination) ++--SKIPIF-- ++<?php ++if (!extension_loaded("zip")) die("skip zip extension not available"); ++?> ++--FILE-- ++<?php ++$zip = new ZipArchive(); ++$zip->open(__DIR__ . "/bug81420.zip"); ++$destination = __DIR__ . "/bug81420"; ++mkdir($destination); ++$zip->extractTo($destination); ++var_dump(file_exists("$destination/nt1/zzr_noharm.php")); ++?> ++--CLEAN-- ++<?php ++$destination = __DIR__ . "/bug81420"; ++@unlink("$destination/nt1/zzr_noharm.php"); ++@rmdir("$destination/nt1"); ++@rmdir($destination); ++?> ++--EXPECT-- ++bool(true) +--- /dev/null ++++ b/ext/zip/tests/bug81420.zip +@@ -0,0 +1,2 @@ ++PK ++ +\ No newline at end of file +diff --git a/ext/dom/domimplementation.c b/ext/dom/domimplementation.c +index 28e35eb..f4d1358 100644 +--- a/ext/dom/domimplementation.c ++++ b/ext/dom/domimplementation.c +@@ -114,6 +114,11 @@ + pch2 = (xmlChar *) systemid; + } + ++ if (strstr(name, "%00")) { ++ php_error_docref(NULL, E_WARNING, "URI must not contain percent-encoded NUL bytes"); ++ RETURN_FALSE; ++ } ++ + uri = xmlParseURI(name); + if (uri != NULL && uri->opaque != NULL) { + localname = xmlStrdup((xmlChar *) uri->opaque); +--- /dev/null ++++ b/ext/dom/tests/bug79971_2.phpt +@@ -0,0 +1,20 @@ ++--TEST-- ++Bug #79971 (special character is breaking the path in xml function) ++--SKIPIF-- ++<?php ++if (!extension_loaded('dom')) die('skip dom extension not available'); ++?> ++--FILE-- ++<?php ++$imp = new DOMImplementation; ++if (PHP_OS_FAMILY === 'Windows') { ++ $path = '/' . str_replace('\\', '/', __DIR__); ++} else { ++ $path = __DIR__; ++} ++$uri = "file://$path/bug79971_2.xml"; ++var_dump($imp->createDocumentType("$uri%00foo")); ++?> ++--EXPECTF-- ++Warning: DOMImplementation::createDocumentType(): URI must not contain percent-encoded NUL bytes in %s on line %d ++bool(false) +diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c +index 85f239d..98344d1 100644 +--- a/ext/libxml/libxml.c ++++ b/ext/libxml/libxml.c +@@ -308,6 +308,10 @@ + int isescaped=0; + xmlURI *uri; + ++ if (strstr(filename, "%00")) { ++ php_error_docref(NULL, E_WARNING, "URI must not contain percent-encoded NUL bytes"); ++ return NULL; ++ } + + uri = xmlParseURI(filename); + if (uri && (uri->scheme == NULL || +@@ -438,6 +442,11 @@ + if (URI == NULL) + return(NULL); + ++ if (strstr(URI, "%00")) { ++ php_error_docref(NULL, E_WARNING, "URI must not contain percent-encoded NUL bytes"); ++ return NULL; ++ } ++ + puri = xmlParseURI(URI); + if (puri != NULL) { + if (puri->scheme != NULL) +--- /dev/null ++++ b/ext/simplexml/tests/bug79971_1.phpt +@@ -0,0 +1,27 @@ ++--TEST-- ++Bug #79971 (special character is breaking the path in xml function) ++--SKIPIF-- ++<?php ++if (!extension_loaded('simplexml')) die('skip simplexml extension not available'); ++?> ++--FILE-- ++<?php ++if (PHP_OS_FAMILY === 'Windows') { ++ $path = '/' . str_replace('\\', '/', __DIR__); ++} else { ++ $path = __DIR__; ++} ++$uri = "file://$path/bug79971_1.xml"; ++var_dump(simplexml_load_file("$uri%00foo")); ++ ++$sxe = simplexml_load_file($uri); ++var_dump($sxe->asXML("$uri.out%00foo")); ++?> ++--EXPECTF-- ++Warning: simplexml_load_file(): URI must not contain percent-encoded NUL bytes in %s on line %d ++ ++Warning: simplexml_load_file(): I/O warning : failed to load external entity "%s/bug79971_1.xml%00foo" in %s on line %d ++bool(false) ++ ++Warning: SimpleXMLElement::asXML(): URI must not contain percent-encoded NUL bytes in %s on line %d ++bool(false) +--- /dev/null ++++ b/ext/simplexml/tests/bug79971_1.xml +@@ -0,0 +1,2 @@ ++<?xml version="1.0"?> ++<root></root> |