diff --git a/ext/standard/proc_open.c b/ext/standard/proc_open.c index 9aa5f74..81368fd 100644 --- a/ext/standard/proc_open.c +++ b/ext/standard/proc_open.c @@ -57,7 +57,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 # include # define PHP_CAN_DO_PTS 1 diff --git a/php.ini-development b/php.ini-development index 2cb93e1..c2b4771 100644 --- a/php.ini-development +++ b/php.ini-development @@ -302,6 +302,12 @@ ; or per-virtualhost web server configuration file. ; Note: disables the realpath cache ; 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 bc0fd55..0f270a8 100644 diff --git a/ext/dba/dba.c b/ext/dba/dba.c index a003416..6cd3b4d 100644 --- a/ext/dba/dba.c +++ b/ext/dba/dba.c @@ -53,6 +53,10 @@ #include "php_tcadb.h" #include "php_lmdb.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) @@ -558,6 +562,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 4991df0..7227b3a 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-- + +--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 0f270a8..7d074f7 100644 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 8374857..6c27345 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 6cd3b4d..370ac08 100644 --- a/ext/dba/dba.c +++ b/ext/dba/dba.c @@ -993,7 +993,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 fde9f02..592793c 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/main/SAPI.c b/main/SAPI.c index 6216fd8..0138335 100644 --- a/main/SAPI.c +++ b/main/SAPI.c @@ -1104,6 +1104,56 @@ } } +SAPI_API void sapi_add_request_header(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg) /* {{{ */ +{ + zval *return_value = (zval*)arg; + char *str = NULL; + + ALLOCA_FLAG(use_heap) + + if (var_len > 5 && + var[0] == 'H' && + var[1] == 'T' && + var[2] == 'T' && + var[3] == 'P' && + var[4] == '_') { + + char *p; + + var_len -= 5; + p = var + 5; + var = str = do_alloca(var_len + 1, use_heap); + *str++ = *p++; + while (*p) { + if (*p == '_') { + *str++ = '-'; + p++; + if (*p) { + *str++ = *p++; + } + } else if (*p >= 'A' && *p <= 'Z') { + *str++ = (*p++ - 'A' + 'a'); + } else { + *str++ = *p++; + } + } + *str = 0; + } else if (var_len == sizeof("CONTENT_TYPE")-1 && + memcmp(var, "CONTENT_TYPE", sizeof("CONTENT_TYPE")-1) == 0) { + var = "Content-Type"; + } else if (var_len == sizeof("CONTENT_LENGTH")-1 && + memcmp(var, "CONTENT_LENGTH", sizeof("CONTENT_LENGTH")-1) == 0) { + var = "Content-Length"; + } else { + return; + } + add_assoc_stringl_ex(return_value, var, var_len, val, val_len); + if (str) { + free_alloca(var, use_heap); + } +} +/* }}} */ + /* * Local variables: * tab-width: 4 diff --git a/main/SAPI.h b/main/SAPI.h index 5a5620b..d452240 100644 --- a/main/SAPI.h +++ b/main/SAPI.h @@ -151,6 +151,7 @@ SAPI_API void sapi_activate(void); SAPI_API void sapi_deactivate(void); SAPI_API void sapi_initialize_empty_request(void); +SAPI_API void sapi_add_request_header(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg); END_EXTERN_C() /* diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c index 16bb212..2eed928 100644 --- a/sapi/cgi/cgi_main.c +++ b/sapi/cgi/cgi_main.c @@ -1596,54 +1596,6 @@ } /* }}} */ -static void add_request_header(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg) /* {{{ */ -{ - zval *return_value = (zval*)arg; - char *str = NULL; - char *p; - ALLOCA_FLAG(use_heap) - - if (var_len > 5 && - var[0] == 'H' && - var[1] == 'T' && - var[2] == 'T' && - var[3] == 'P' && - var[4] == '_') { - - var_len -= 5; - p = var + 5; - var = str = do_alloca(var_len + 1, use_heap); - *str++ = *p++; - while (*p) { - if (*p == '_') { - *str++ = '-'; - p++; - if (*p) { - *str++ = *p++; - } - } else if (*p >= 'A' && *p <= 'Z') { - *str++ = (*p++ - 'A' + 'a'); - } else { - *str++ = *p++; - } - } - *str = 0; - } else if (var_len == sizeof("CONTENT_TYPE")-1 && - memcmp(var, "CONTENT_TYPE", sizeof("CONTENT_TYPE")-1) == 0) { - var = "Content-Type"; - } else if (var_len == sizeof("CONTENT_LENGTH")-1 && - memcmp(var, "CONTENT_LENGTH", sizeof("CONTENT_LENGTH")-1) == 0) { - var = "Content-Length"; - } else { - return; - } - add_assoc_stringl_ex(return_value, var, var_len, val, val_len); - if (str) { - free_alloca(var, use_heap); - } -} -/* }}} */ - PHP_FUNCTION(apache_request_headers) /* {{{ */ { if (zend_parse_parameters_none()) { @@ -1653,7 +1605,7 @@ if (fcgi_is_fastcgi()) { fcgi_request *request = (fcgi_request*) SG(server_context); - fcgi_loadenv(request, add_request_header, return_value); + fcgi_loadenv(request, sapi_add_request_header, return_value); } else { char buf[128]; char **env, *p, *q, *var, *val, *t = buf; diff --git a/sapi/fpm/fpm/fpm_main.c b/sapi/fpm/fpm/fpm_main.c index b0e6226..702946a 100644 --- a/sapi/fpm/fpm/fpm_main.c +++ b/sapi/fpm/fpm/fpm_main.c @@ -1533,6 +1533,10 @@ { fcgi_request *request = (fcgi_request*) SG(server_context); + if (zend_parse_parameters_none() == FAILURE) { + return; + } + if (!fcgi_is_closed(request)) { php_output_end_all(); php_header(); @@ -1547,8 +1551,27 @@ } /* }}} */ +ZEND_BEGIN_ARG_INFO(cgi_fcgi_sapi_no_arginfo, 0) +ZEND_END_ARG_INFO() + +PHP_FUNCTION(apache_request_headers) /* {{{ */ +{ + fcgi_request *request; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + array_init(return_value); + if ((request = (fcgi_request*) SG(server_context))) { + fcgi_loadenv(request, sapi_add_request_header, return_value); + } +} /* }}} */ + static const zend_function_entry cgi_fcgi_sapi_functions[] = { - PHP_FE(fastcgi_finish_request, NULL) + PHP_FE(fastcgi_finish_request, cgi_fcgi_sapi_no_arginfo) + PHP_FE(apache_request_headers, cgi_fcgi_sapi_no_arginfo) + PHP_FALIAS(getallheaders, apache_request_headers, cgi_fcgi_sapi_no_arginfo) PHP_FE_END }; --- /dev/null +++ b/sapi/fpm/tests/getallheaders.phpt @@ -0,0 +1,67 @@ +--TEST-- +FPM: Function getallheaders basic test +--SKIPIF-- + +--FILE-- +start(); +$tester->expectLogStartNotices(); +$tester->request( + '', + [ + 'HTTP_X_FOO' => 'BAR', + 'HTTP_FOO' => 'foo' + ] + )->expectBody( + [ + 'Test Start', + 'array(4) {', + ' ["Foo"]=>', + ' string(3) "foo"', + ' ["X-Foo"]=>', + ' string(3) "BAR"', + ' ["Content-Length"]=>', + ' string(1) "0"', + ' ["Content-Type"]=>', + ' string(0) ""', + '}', + 'Test End', + ] + ); +$tester->terminate(); +$tester->expectLogTerminatingNotices(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index 6b29266..af1d8db 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -1477,6 +1477,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/sapi/fpm/tests/tester.inc b/sapi/fpm/tests/tester.inc index 89bbb90..5335d76 100644 --- a/sapi/fpm/tests/tester.inc +++ b/sapi/fpm/tests/tester.inc @@ -860,7 +860,17 @@ { $port = $this->getPort($type, $pool, true); if ($type === 'uds') { - return $this->getFile($port . '.sock'); + $address = $this->getFile($port . '.sock'); + + // Socket max path length is 108 on Linux and 104 on BSD, + // so we use the latter + if (strlen($address) <= 104) { + return $address; + } + + return sys_get_temp_dir().'/'. + hash('crc32', dirname($address)).'-'. + basename($address); } return $this->getHost($type) . ':' . $port; 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-- + +--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/tests/url/parse_url_unterminated.phpt b/ext/standard/tests/url/parse_url_unterminated.phpt index 912b6a5..875d93a 100644 --- a/ext/standard/tests/url/parse_url_unterminated.phpt +++ b/ext/standard/tests/url/parse_url_unterminated.phpt @@ -508,15 +508,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/url.c b/ext/standard/url.c index 1dd073e..8d155bb 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 37eb5e1..9cac226 100644 --- a/ext/imap/php_imap.c +++ b/ext/imap/php_imap.c @@ -3528,6 +3528,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) @@ -3548,6 +3565,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"); \ @@ -3556,46 +3580,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)); } @@ -3605,6 +3640,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); @@ -3637,6 +3673,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"); @@ -3647,9 +3684,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; @@ -3660,18 +3699,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); } @@ -3679,9 +3722,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; @@ -3710,6 +3755,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) { @@ -3740,6 +3786,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); @@ -3751,9 +3798,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; @@ -3764,18 +3813,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); } @@ -3783,9 +3836,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; @@ -3814,6 +3869,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-- + +--FILE-- + +--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-- + +--FILE-- + +--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 1c0f5b6..c5e6b68 100644 --- a/ext/pdo_firebird/firebird_statement.c +++ b/ext/pdo_firebird/firebird_statement.c @@ -294,6 +294,11 @@ unsigned short seg_len; ISC_STATUS stat; + /* prevent overflow */ + if (*len == ZEND_ULONG_MAX) { + result = 0; + goto fetch_blob_end; + } *ptr = S->fetch_buf[colno] = erealloc(S->fetch_buf[colno], *len+1); for (cur_len = stat = 0; (!stat || stat == isc_segment) && cur_len < *len; cur_len += seg_len) { --- /dev/null +++ b/ext/pdo_firebird/tests/bug_76452.data @@ -0,0 +1 @@ +^ÿÿ€ Legacy_Auth\ Legacy_Auth    ¡  Á  2AAATESTSYSDBAAAA     BBBBTESTSYSDBABBBB  Bhihi‹Bhihi2‹Bhihi2‹Bhihi2‹Bd  ÿÿÿÿ 123   ÿÿÿÿ   \ No newline at end of file --- /dev/null +++ b/ext/pdo_firebird/tests/bug_76452.phpt @@ -0,0 +1,31 @@ +--TEST-- +Bug ##76452 (Crash while parsing blob data in firebird_fetch_blob) +--SKIPIF-- + +--FILE-- + PDO::ERRMODE_EXCEPTION]); +$query = $dbh->prepare("select * from test"); +$query->execute(); +var_dump($query->fetch()); +?> +--EXPECT-- +array(4) { + ["AAA"]=> + string(4) "hihi" + [0]=> + string(4) "hihi" + ["BBBB"]=> + NULL + [1]=> + NULL +} 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 @@ +^ÿÿ€ Legacy_Auth\ Legacy_Auth      !ÿÿþÿ   ÿÿÿÿ   \ 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-- + +--FILE-- + 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 34e234a..fb9dbaa 100644 --- a/ext/pdo_firebird/firebird_driver.c +++ b/ext/pdo_firebird/firebird_driver.c @@ -205,8 +205,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 @@ +^ÿÿ€ Legacy_Auth\ Legacy_Auth      !ÿÿþÿ   ÿÿÿÿ   \ 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-- + +--FILE-- + 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 fb9dbaa..48e8ec6 100644 --- a/ext/pdo_firebird/firebird_driver.c +++ b/ext/pdo_firebird/firebird_driver.c @@ -508,14 +508,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); } } /* }}} */ @@ -526,7 +528,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 @@ +^ÿÿ€ Legacy_Auth\ Legacy_Auth   @g$"WI-T4.0.0.998 Firebird 4.0 Alpha 1ÿWI-T4.0.0.998 Firebird 4.0 Alpha 1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa DDr  \ 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-- + +--FILE-- + PDO::ERRMODE_EXCEPTION]); +var_dump($dbh->getAttribute(PDO::ATTR_SERVER_INFO)); +?> +--EXPECT-- +bool(false) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 2987b64..01bdc05 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -1440,6 +1440,7 @@ zend_class_entry *ce = p_obj->c; phar_archive_object *phar_obj = p_obj->p; php_stream_statbuf ssb; + char ch; value = iter->funcs->get_current_data(iter); @@ -1569,7 +1570,7 @@ base = temp; base_len = (int)strlen(base); - if (strstr(fname, base)) { + if (fname_len >= base_len && strncmp(fname, base, base_len) == 0 && ((ch = fname[base_len - IS_SLASH(base[base_len - 1])]) == '\0' || IS_SLASH(ch))) { str_key_len = fname_len - base_len; if (str_key_len <= 0) { --- /dev/null +++ b/ext/phar/tests/bug81211.phpt @@ -0,0 +1,45 @@ +--TEST-- +Bug #81211 (Symlinks are followed when creating PHAR archive) +--SKIPIF-- + +--FILE-- +buildFromDirectory(__DIR__ . '/bug81211/foo'); +} catch (UnexpectedValueException $ex) { + echo $ex->getMessage(), PHP_EOL; +} +try { + $archive->buildFromIterator(new RecursiveDirectoryIterator(__DIR__ . '/bug81211/foo', FilesystemIterator::SKIP_DOTS), __DIR__ . '/bug81211/foo'); +} catch (UnexpectedValueException $ex) { + echo $ex->getMessage(), PHP_EOL; +} +?> +--CLEAN-- + +--EXPECTF-- +Iterator RecursiveIteratorIterator returned a path "%s%ebug81211\foobar\file" that is not in the base directory "%s%ebug81211\foo" +Iterator RecursiveDirectoryIterator returned a path "%s%ebug81211\foobar\file" that is not in the base directory "%s%ebug81211\foo" diff --git a/ext/standard/tests/file/windows_links/common.inc b/ext/standard/tests/file/windows_links/common.inc index 505368b..caa3758 100644 --- a/ext/standard/tests/file/windows_links/common.inc +++ b/ext/standard/tests/file/windows_links/common.inc @@ -20,4 +20,11 @@ return "$sysroot\\System32\\mountvol.exe"; } -?> +function skipIfSeCreateSymbolicLinkPrivilegeIsDisabled(string $filename) { + $ln = "$filename.lnk"; + $ret = exec("mklink $ln " . __FILE__ .' 2>&1', $out); + @unlink($ln); + if (strpos($ret, 'privilege') !== false) { + die('skip SeCreateSymbolicLinkPrivilege not enabled'); + } +} diff --git a/sapi/fpm/fpm/fpm_children.c b/sapi/fpm/fpm/fpm_children.c index eed0c67..05513f0 100644 --- a/sapi/fpm/fpm/fpm_children.c +++ b/sapi/fpm/fpm/fpm_children.c @@ -243,7 +243,7 @@ fpm_child_unlink(child); - fpm_scoreboard_proc_free(wp->scoreboard, child->scoreboard_i); + fpm_scoreboard_proc_free(child); fpm_clock_get(&tv1); @@ -253,9 +253,9 @@ if (!fpm_pctl_can_spawn_children()) { severity = ZLOG_DEBUG; } - zlog(severity, "[pool %s] child %d exited %s after %ld.%06d seconds from start", child->wp->config->name, (int) pid, buf, tv2.tv_sec, (int) tv2.tv_usec); + zlog(severity, "[pool %s] child %d exited %s after %ld.%06d seconds from start", wp->config->name, (int) pid, buf, tv2.tv_sec, (int) tv2.tv_usec); } else { - zlog(ZLOG_DEBUG, "[pool %s] child %d has been killed by the process management after %ld.%06d seconds from start", child->wp->config->name, (int) pid, tv2.tv_sec, (int) tv2.tv_usec); + zlog(ZLOG_DEBUG, "[pool %s] child %d has been killed by the process management after %ld.%06d seconds from start", wp->config->name, (int) pid, tv2.tv_sec, (int) tv2.tv_usec); } fpm_child_close(child, 1 /* in event_loop */); @@ -321,7 +321,7 @@ return 0; } - if (0 > fpm_scoreboard_proc_alloc(wp->scoreboard, &c->scoreboard_i)) { + if (0 > fpm_scoreboard_proc_alloc(c)) { fpm_stdio_discard_pipes(c); fpm_child_free(c); return 0; @@ -333,7 +333,7 @@ static void fpm_resources_discard(struct fpm_child_s *child) /* {{{ */ { - fpm_scoreboard_proc_free(child->wp->scoreboard, child->scoreboard_i); + fpm_scoreboard_proc_free(child); fpm_stdio_discard_pipes(child); fpm_child_free(child); } @@ -346,10 +346,10 @@ if (wp == child->wp) { continue; } - fpm_scoreboard_free(wp->scoreboard); + fpm_scoreboard_free(wp); } - fpm_scoreboard_child_use(child->wp->scoreboard, child->scoreboard_i, getpid()); + fpm_scoreboard_child_use(child, getpid()); fpm_stdio_child_use_pipes(child); fpm_child_free(child); } diff --git a/sapi/fpm/fpm/fpm_request.c b/sapi/fpm/fpm/fpm_request.c index a4ace85..deaccf4 100644 --- a/sapi/fpm/fpm/fpm_request.c +++ b/sapi/fpm/fpm/fpm_request.c @@ -286,7 +286,7 @@ struct fpm_scoreboard_proc_s *proc; /* no need in atomicity here */ - proc = fpm_scoreboard_proc_get(child->wp->scoreboard, child->scoreboard_i); + proc = fpm_scoreboard_proc_get_from_child(child); if (!proc) { return 0; } @@ -301,7 +301,7 @@ if (!tv) return -1; - proc = fpm_scoreboard_proc_get(child->wp->scoreboard, child->scoreboard_i); + proc = fpm_scoreboard_proc_get_from_child(child); if (!proc) { return -1; } diff --git a/sapi/fpm/fpm/fpm_scoreboard.c b/sapi/fpm/fpm/fpm_scoreboard.c index 7a65fcb..091efdc 100644 --- a/sapi/fpm/fpm/fpm_scoreboard.c +++ b/sapi/fpm/fpm/fpm_scoreboard.c @@ -7,6 +7,7 @@ #include #include "fpm_config.h" +#include "fpm_children.h" #include "fpm_scoreboard.h" #include "fpm_shm.h" #include "fpm_sockets.h" @@ -24,7 +25,6 @@ int fpm_scoreboard_init_main() /* {{{ */ { struct fpm_worker_pool_s *wp; - unsigned int i; #ifdef HAVE_TIMES #if (defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK)) @@ -41,7 +41,7 @@ for (wp = fpm_worker_all_pools; wp; wp = wp->next) { - size_t scoreboard_size, scoreboard_nprocs_size; + size_t scoreboard_procs_size; void *shm_mem; if (wp->config->pm_max_children < 1) { @@ -54,22 +54,15 @@ return -1; } - scoreboard_size = sizeof(struct fpm_scoreboard_s) + (wp->config->pm_max_children) * sizeof(struct fpm_scoreboard_proc_s *); - scoreboard_nprocs_size = sizeof(struct fpm_scoreboard_proc_s) * wp->config->pm_max_children; - shm_mem = fpm_shm_alloc(scoreboard_size + scoreboard_nprocs_size); + scoreboard_procs_size = sizeof(struct fpm_scoreboard_proc_s) * wp->config->pm_max_children; + shm_mem = fpm_shm_alloc(sizeof(struct fpm_scoreboard_s) + scoreboard_procs_size); if (!shm_mem) { return -1; } - wp->scoreboard = shm_mem; + wp->scoreboard = shm_mem; + wp->scoreboard->pm = wp->config->pm; wp->scoreboard->nprocs = wp->config->pm_max_children; - shm_mem += scoreboard_size; - - for (i = 0; i < wp->scoreboard->nprocs; i++, shm_mem += sizeof(struct fpm_scoreboard_proc_s)) { - wp->scoreboard->procs[i] = shm_mem; - } - - wp->scoreboard->pm = wp->config->pm; wp->scoreboard->start_epoch = time(NULL); strlcpy(wp->scoreboard->pool, wp->config->name, sizeof(wp->scoreboard->pool)); } @@ -163,28 +156,48 @@ } /* }}} */ -struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get(struct fpm_scoreboard_s *scoreboard, int child_index) /* {{{*/ +static inline struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get_ex( + struct fpm_scoreboard_s *scoreboard, int child_index, unsigned int nprocs) /* {{{*/ { if (!scoreboard) { - scoreboard = fpm_scoreboard; + return NULL; } - if (!scoreboard) { + if (child_index < 0 || (unsigned int)child_index >= nprocs) { return NULL; } + return &scoreboard->procs[child_index]; +} +/* }}} */ + +struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get( + struct fpm_scoreboard_s *scoreboard, int child_index) /* {{{*/ +{ + if (!scoreboard) { + scoreboard = fpm_scoreboard; + } + if (child_index < 0) { child_index = fpm_scoreboard_i; } - if (child_index < 0 || (unsigned int)child_index >= scoreboard->nprocs) { - return NULL; - } + return fpm_scoreboard_proc_get_ex(scoreboard, child_index, scoreboard->nprocs); +} +/* }}} */ - return scoreboard->procs[child_index]; +struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get_from_child(struct fpm_child_s *child) /* {{{*/ +{ + struct fpm_worker_pool_s *wp = child->wp; + unsigned int nprocs = wp->config->pm_max_children; + struct fpm_scoreboard_s *scoreboard = wp->scoreboard; + int child_index = child->scoreboard_i; + + return fpm_scoreboard_proc_get_ex(scoreboard, child_index, nprocs); } /* }}} */ + struct fpm_scoreboard_s *fpm_scoreboard_acquire(struct fpm_scoreboard_s *scoreboard, int nohang) /* {{{ */ { struct fpm_scoreboard_s *s; @@ -235,28 +248,28 @@ proc->lock = 0; } -void fpm_scoreboard_free(struct fpm_scoreboard_s *scoreboard) /* {{{ */ +void fpm_scoreboard_free(struct fpm_worker_pool_s *wp) /* {{{ */ { - size_t scoreboard_size, scoreboard_nprocs_size; + size_t scoreboard_procs_size; + struct fpm_scoreboard_s *scoreboard = wp->scoreboard; if (!scoreboard) { zlog(ZLOG_ERROR, "**scoreboard is NULL"); return; } - scoreboard_size = sizeof(struct fpm_scoreboard_s) + (scoreboard->nprocs) * sizeof(struct fpm_scoreboard_proc_s *); - scoreboard_nprocs_size = sizeof(struct fpm_scoreboard_proc_s) * scoreboard->nprocs; + scoreboard_procs_size = sizeof(struct fpm_scoreboard_proc_s) * wp->config->pm_max_children; - fpm_shm_free(scoreboard, scoreboard_size + scoreboard_nprocs_size); + fpm_shm_free(scoreboard, sizeof(struct fpm_scoreboard_s) + scoreboard_procs_size); } /* }}} */ -void fpm_scoreboard_child_use(struct fpm_scoreboard_s *scoreboard, int child_index, pid_t pid) /* {{{ */ +void fpm_scoreboard_child_use(struct fpm_child_s *child, pid_t pid) /* {{{ */ { struct fpm_scoreboard_proc_s *proc; - fpm_scoreboard = scoreboard; - fpm_scoreboard_i = child_index; - proc = fpm_scoreboard_proc_get(scoreboard, child_index); + fpm_scoreboard = child->wp->scoreboard; + fpm_scoreboard_i = child->scoreboard_i; + proc = fpm_scoreboard_proc_get_from_child(child); if (!proc) { return; } @@ -265,18 +278,22 @@ } /* }}} */ -void fpm_scoreboard_proc_free(struct fpm_scoreboard_s *scoreboard, int child_index) /* {{{ */ +void fpm_scoreboard_proc_free(struct fpm_child_s *child) /* {{{ */ { + struct fpm_worker_pool_s *wp = child->wp; + struct fpm_scoreboard_s *scoreboard = wp->scoreboard; + int child_index = child->scoreboard_i; + if (!scoreboard) { return; } - if (child_index < 0 || (unsigned int)child_index >= scoreboard->nprocs) { + if (child_index < 0 || child_index >= wp->config->pm_max_children) { return; } - if (scoreboard->procs[child_index] && scoreboard->procs[child_index]->used > 0) { - memset(scoreboard->procs[child_index], 0, sizeof(struct fpm_scoreboard_proc_s)); + if (scoreboard->procs[child_index].used > 0) { + memset(&scoreboard->procs[child_index], 0, sizeof(struct fpm_scoreboard_proc_s)); } /* set this slot as free to avoid search on next alloc */ @@ -284,41 +301,44 @@ } /* }}} */ -int fpm_scoreboard_proc_alloc(struct fpm_scoreboard_s *scoreboard, int *child_index) /* {{{ */ +int fpm_scoreboard_proc_alloc(struct fpm_child_s *child) /* {{{ */ { int i = -1; + struct fpm_worker_pool_s *wp = child->wp; + struct fpm_scoreboard_s *scoreboard = wp->scoreboard; + int nprocs = wp->config->pm_max_children; - if (!scoreboard || !child_index) { + if (!scoreboard) { return -1; } /* first try the slot which is supposed to be free */ - if (scoreboard->free_proc >= 0 && (unsigned int)scoreboard->free_proc < scoreboard->nprocs) { - if (scoreboard->procs[scoreboard->free_proc] && !scoreboard->procs[scoreboard->free_proc]->used) { + if (scoreboard->free_proc >= 0 && scoreboard->free_proc < nprocs) { + if (!scoreboard->procs[scoreboard->free_proc].used) { i = scoreboard->free_proc; } } if (i < 0) { /* the supposed free slot is not, let's search for a free slot */ zlog(ZLOG_DEBUG, "[pool %s] the proc->free_slot was not free. Let's search", scoreboard->pool); - for (i = 0; i < (int)scoreboard->nprocs; i++) { - if (scoreboard->procs[i] && !scoreboard->procs[i]->used) { /* found */ + for (i = 0; i < nprocs; i++) { + if (!scoreboard->procs[i].used) { /* found */ break; } } } /* no free slot */ - if (i < 0 || i >= (int)scoreboard->nprocs) { + if (i < 0 || i >= nprocs) { zlog(ZLOG_ERROR, "[pool %s] no free scoreboard slot", scoreboard->pool); return -1; } - scoreboard->procs[i]->used = 1; - *child_index = i; + scoreboard->procs[i].used = 1; + child->scoreboard_i = i; /* supposed next slot is free */ - if (i + 1 >= (int)scoreboard->nprocs) { + if (i + 1 >= nprocs) { scoreboard->free_proc = 0; } else { scoreboard->free_proc = i + 1; diff --git a/sapi/fpm/fpm/fpm_scoreboard.h b/sapi/fpm/fpm/fpm_scoreboard.h index abce616..6405abb 100644 --- a/sapi/fpm/fpm/fpm_scoreboard.h +++ b/sapi/fpm/fpm/fpm_scoreboard.h @@ -64,7 +64,7 @@ unsigned int nprocs; int free_proc; unsigned long int slow_rq; - struct fpm_scoreboard_proc_s *procs[]; + struct fpm_scoreboard_proc_s procs[]; }; int fpm_scoreboard_init_main(); @@ -73,18 +73,19 @@ void fpm_scoreboard_update(int idle, int active, int lq, int lq_len, int requests, int max_children_reached, int slow_rq, int action, struct fpm_scoreboard_s *scoreboard); struct fpm_scoreboard_s *fpm_scoreboard_get(); struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get(struct fpm_scoreboard_s *scoreboard, int child_index); +struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get_from_child(struct fpm_child_s *child); struct fpm_scoreboard_s *fpm_scoreboard_acquire(struct fpm_scoreboard_s *scoreboard, int nohang); void fpm_scoreboard_release(struct fpm_scoreboard_s *scoreboard); struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_acquire(struct fpm_scoreboard_s *scoreboard, int child_index, int nohang); void fpm_scoreboard_proc_release(struct fpm_scoreboard_proc_s *proc); -void fpm_scoreboard_free(struct fpm_scoreboard_s *scoreboard); +void fpm_scoreboard_free(struct fpm_worker_pool_s *wp); -void fpm_scoreboard_child_use(struct fpm_scoreboard_s *scoreboard, int child_index, pid_t pid); +void fpm_scoreboard_child_use(struct fpm_child_s *child, pid_t pid); -void fpm_scoreboard_proc_free(struct fpm_scoreboard_s *scoreboard, int child_index); -int fpm_scoreboard_proc_alloc(struct fpm_scoreboard_s *scoreboard, int *child_index); +void fpm_scoreboard_proc_free(struct fpm_child_s *child); +int fpm_scoreboard_proc_alloc(struct fpm_child_s *child); #ifdef HAVE_TIMES float fpm_scoreboard_get_tick(); diff --git a/sapi/fpm/fpm/fpm_status.c b/sapi/fpm/fpm/fpm_status.c index 1d78ebf..45852a5 100644 --- a/sapi/fpm/fpm/fpm_status.c +++ b/sapi/fpm/fpm/fpm_status.c @@ -402,10 +402,10 @@ first = 1; for (i=0; inprocs; i++) { - if (!scoreboard_p->procs[i] || !scoreboard_p->procs[i]->used) { + if (!scoreboard_p->procs[i].used) { continue; } - proc = *scoreboard_p->procs[i]; + proc = scoreboard_p->procs[i]; if (first) { first = 0; diff --git a/sapi/fpm/fpm/fpm_worker_pool.c b/sapi/fpm/fpm/fpm_worker_pool.c index 90e1559..96b7ca5 100644 --- a/sapi/fpm/fpm/fpm_worker_pool.c +++ b/sapi/fpm/fpm/fpm_worker_pool.c @@ -43,7 +43,7 @@ fpm_worker_pool_config_free(wp->config); fpm_children_free(wp->children); if ((which & FPM_CLEANUP_CHILD) == 0 && fpm_globals.parent_pid == getpid()) { - fpm_scoreboard_free(wp->scoreboard); + fpm_scoreboard_free(wp); } fpm_worker_pool_free(wp); } diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index af1d8db..c467a81 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -106,8 +106,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-- + +--FILE-- +open(__DIR__ . "/bug81420.zip"); +$destination = __DIR__ . "/bug81420"; +mkdir($destination); +$zip->extractTo($destination); +var_dump(file_exists("$destination/nt1/zzr_noharm.php")); +?> +--CLEAN-- + +--EXPECT-- +bool(true) --- /dev/null +++ b/ext/zip/tests/bug81420.zip @@ -0,0 +1,2 @@ +PK›¦#S€õŒ(2/../nt1/zzr_noharm.phpË­ÌKÌMÍ,®ª*ŠÏËÏH,ÊÕ+È(P°µSàåÒ×ÓÓÏ+1ÔG•PK›¦#S€õŒ(2$ /../nt1/zzr_noharm.php + R®¦›Â ×å¿ý“ ×å¿ý“ ×PKh\ \ 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-- + +--FILE-- +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 c871cb8..da553d6 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-- + +--FILE-- +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 @@ + +