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 # include # 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 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-- + +--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 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 */ 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-- + +--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-- + +--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-- +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-- + +--FILE-- + '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-- + +--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-- + +--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-- + +--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-- + +--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-- + +--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-- + +--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 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 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 @@ +^ÿÿ€ 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 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 @@ +^ÿÿ€ 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/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-- + +--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 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-- + +--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 @@ + +