From a4ce88ee0ddf7e29c5ed3e003ea18b7808390ae2 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Tue, 14 Feb 2017 13:51:07 +0100 Subject: php-pecl-zendopcache: backport security fix for bug #69090 --- opcache.ini | 11 ++ php-pecl-zendopcache.spec | 9 +- zendopcache-bug69090.patch | 299 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 zendopcache-bug69090.patch diff --git a/opcache.ini b/opcache.ini index c26c351..b195df6 100644 --- a/opcache.ini +++ b/opcache.ini @@ -93,3 +93,14 @@ opcache.blacklist_filename=@INIPATH@/opcache*.blacklist ; Useful for internal debugging only. ;opcache.protect_memory=0 +; Validate cached file permissions. +; Leads OPcache to check file readability on each access to cached file. +; This directive should be enabled in shared hosting environment, when few +; users (PHP-FPM pools) reuse the common OPcache shared memory. +;opcache.validate_permission=0 + +; Prevent name collisions in chroot'ed environment. +; This directive prevents file name collisions in different "chroot" +; environments. It should be enabled for sites that may serve requests in +; different "chroot" environments. +;opcache.validate_root=0 diff --git a/php-pecl-zendopcache.spec b/php-pecl-zendopcache.spec index 010e5f2..de9b15c 100644 --- a/php-pecl-zendopcache.spec +++ b/php-pecl-zendopcache.spec @@ -15,7 +15,7 @@ Name: %{?scl_prefix}php-pecl-%{pecl_name} Version: 7.0.5 -Release: 2%{?dist} +Release: 3%{?dist} Summary: The Zend OPcache Group: Development/Libraries @@ -27,6 +27,9 @@ Source0: http://pecl.php.net/get/%{pecl_name}-%{version}.tgz Source1: %{plug_name}.ini Source2: %{plug_name}-default.blacklist +# see https://bugs.php.net/69090 +Patch0: %{pecl_name}-bug69090.patch + BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root BuildRequires: %{?scl_prefix}php-devel >= 5.2.0 BuildRequires: %{?scl_prefix}php-pear @@ -80,6 +83,7 @@ sed -e 's/role="test"/role="src"/' \ -i package.xml pushd NTS +%patch0 -p3 -b .bug69090 # Sanity check, really often broken extver=$(sed -n '/#define PHP_ZENDOPCACHE_VERSION/{s/.*"7/7/;s/".*$//;p}' ZendAccelerator.h) @@ -213,6 +217,9 @@ fi %changelog +* Thu Feb 9 2017 Remi Collet - 7.0.5-3 +- backport security fix for bug #69090, rhbz#1409317 + * Thu Mar 10 2016 Remi Collet - 7.0.5-2 - adapt for F24 diff --git a/zendopcache-bug69090.patch b/zendopcache-bug69090.patch new file mode 100644 index 0000000..cc0d6d7 --- /dev/null +++ b/zendopcache-bug69090.patch @@ -0,0 +1,299 @@ +Backported for pecl extension from php 5.6 +Using + + +From ecba563f2fa1e027ea91b9ee0d50611273852995 Mon Sep 17 00:00:00 2001 +From: Dmitry Stogov +Date: Wed, 16 Nov 2016 12:43:10 +0300 +Subject: [PATCH] Fixed bug #69090 (check cached files permissions) + +--- + NEWS | 1 + + ext/opcache/README | 10 ++++++++ + ext/opcache/ZendAccelerator.c | 47 +++++++++++++++++++++++++++++++++++ + ext/opcache/ZendAccelerator.h | 5 ++++ + ext/opcache/zend_accelerator_hash.c | 12 +++++++++ + ext/opcache/zend_accelerator_module.c | 4 +++ + 6 files changed, 79 insertions(+) + +diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c +index 985a4ef..c8d2290 100644 +--- a/ext/opcache/ZendAccelerator.c ++++ b/ext/opcache/ZendAccelerator.c +@@ -1559,6 +1559,28 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type T + persistent_script = NULL; + } + ++ /* Revalidate acessibility of cached file */ ++ if (EXPECTED(persistent_script != NULL) && ++ UNEXPECTED(ZCG(accel_directives).validate_permission) && ++ file_handle->type == ZEND_HANDLE_FILENAME && ++ UNEXPECTED(access(file_handle->filename, R_OK) != 0)) { ++ if (type == ZEND_REQUIRE) { ++#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO ++ zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename); ++#else ++ zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename TSRMLS_CC); ++#endif ++ zend_bailout(); ++ } else { ++#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO ++ zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename); ++#else ++ zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename TSRMLS_CC); ++#endif ++ } ++ return NULL; ++ } ++ + SHM_UNPROTECT(); + + /* If script is found then validate_timestamps if option is enabled */ +@@ -2071,6 +2093,31 @@ static void accel_activate(void) + return; + } + ++#ifndef ZEND_WIN32 ++ if (ZCG(accel_directives).validate_root) { ++ struct stat buf; ++ ++ if (stat("/", &buf) != 0) { ++ ZCG(root_hash) = 0; ++ } else { ++ unsigned long x = buf.st_ino; ++ ++#if SIZEOF_LONG == 4 ++ x = ((x >> 16) ^ x) * 0x45d9f3b; ++ x = ((x >> 16) ^ x) * 0x45d9f3b; ++ x = (x >> 16) ^ x; ++#elif SIZEOF_LONG == 8 ++ x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9; ++ x = (x ^ (x >> 27)) * 0x94d049bb133111eb; ++ x = x ^ (x >> 31); ++#endif ++ ZCG(root_hash) = x; ++ } ++ } else { ++ ZCG(root_hash) = 0; ++ } ++#endif ++ + SHM_UNPROTECT(); + /* PHP-5.4 and above return "double", but we use 1 sec precision */ + ZCG(request_time) = (time_t)sapi_get_request_time(TSRMLS_C); +diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h +index 11942f1..a711de7 100644 +--- a/ext/opcache/ZendAccelerator.h ++++ b/ext/opcache/ZendAccelerator.h +@@ -229,6 +229,8 @@ typedef struct _zend_accel_directives { + zend_bool file_override_enabled; + zend_bool inherited_hack; + zend_bool enable_cli; ++ zend_bool validate_permission; ++ zend_bool validate_root; + unsigned long revalidate_freq; + unsigned long file_update_protection; + char *error_log; +@@ -263,6 +265,9 @@ typedef struct _zend_accel_globals { + int include_path_len; /* "include_path" string length */ + int include_path_check; + time_t request_time; ++#ifndef ZEND_WIN32 ++ unsigned long root_hash; ++#endif + /* preallocated shared-memory block to save current script */ + void *mem; + /* cache to save hash lookup on the same INCLUDE opcode */ +diff --git a/ext/opcache/zend_accelerator_hash.c b/ext/opcache/zend_accelerator_hash.c +index 992885f..4b8b712 100644 +--- a/ext/opcache/zend_accelerator_hash.c ++++ b/ext/opcache/zend_accelerator_hash.c +@@ -86,6 +86,9 @@ zend_accel_hash_entry* zend_accel_hash_update(zend_accel_hash *accel_hash, char + } + + hash_value = zend_inline_hash_func(key, key_length); ++#ifndef ZEND_WIN32 ++ hash_value ^= ZCG(root_hash); ++#endif + index = hash_value % accel_hash->max_num_entries; + + /* try to see if the element already exists in the hash */ +@@ -147,6 +150,9 @@ void* zend_accel_hash_find(zend_accel_hash *accel_hash, char *key, zend_uint key + zend_accel_hash_entry *entry; + + hash_value = zend_inline_hash_func(key, key_length); ++#ifndef ZEND_WIN32 ++ hash_value ^= ZCG(root_hash); ++#endif + index = hash_value % accel_hash->max_num_entries; + + entry = accel_hash->hash_table[index]; +@@ -175,6 +181,9 @@ zend_accel_hash_entry* zend_accel_hash_find_entry(zend_accel_hash *accel_hash, c + zend_accel_hash_entry *entry; + + hash_value = zend_inline_hash_func(key, key_length); ++#ifndef ZEND_WIN32 ++ hash_value ^= ZCG(root_hash); ++#endif + index = hash_value % accel_hash->max_num_entries; + + entry = accel_hash->hash_table[index]; +@@ -200,6 +209,9 @@ int zend_accel_hash_unlink(zend_accel_hash *accel_hash, char *key, zend_uint key + zend_accel_hash_entry *entry, *last_entry=NULL; + + hash_value = zend_inline_hash_func(key, key_length); ++#ifndef ZEND_WIN32 ++ hash_value ^= ZCG(root_hash); ++#endif + index = hash_value % accel_hash->max_num_entries; + + entry = accel_hash->hash_table[index]; +diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c +index 5671f2f..0faa915 100644 +--- a/ext/opcache/zend_accelerator_module.c ++++ b/ext/opcache/zend_accelerator_module.c +@@ -251,6 +251,8 @@ ZEND_INI_BEGIN() + STD_PHP_INI_BOOLEAN("opcache.enable" , "1", PHP_INI_ALL, OnEnable, enabled , zend_accel_globals, accel_globals) + STD_PHP_INI_BOOLEAN("opcache.use_cwd" , "1", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.use_cwd , zend_accel_globals, accel_globals) + STD_PHP_INI_BOOLEAN("opcache.validate_timestamps", "1", PHP_INI_ALL , OnUpdateBool, accel_directives.validate_timestamps, zend_accel_globals, accel_globals) ++ STD_PHP_INI_BOOLEAN("opcache.validate_permission", "0", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.validate_permission, zend_accel_globals, accel_globals) ++ STD_PHP_INI_BOOLEAN("opcache.validate_root" , "0", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.validate_root , zend_accel_globals, accel_globals) + STD_PHP_INI_BOOLEAN("opcache.inherited_hack" , "1", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.inherited_hack , zend_accel_globals, accel_globals) + STD_PHP_INI_BOOLEAN("opcache.dups_fix" , "0", PHP_INI_ALL , OnUpdateBool, accel_directives.ignore_dups , zend_accel_globals, accel_globals) + STD_PHP_INI_BOOLEAN("opcache.revalidate_path" , "0", PHP_INI_ALL , OnUpdateBool, accel_directives.revalidate_path , zend_accel_globals, accel_globals) +@@ -659,6 +661,8 @@ static ZEND_FUNCTION(opcache_get_configuration) + add_assoc_bool(directives, "opcache.enable_cli", ZCG(accel_directives).enable_cli); + add_assoc_bool(directives, "opcache.use_cwd", ZCG(accel_directives).use_cwd); + add_assoc_bool(directives, "opcache.validate_timestamps", ZCG(accel_directives).validate_timestamps); ++ add_assoc_bool(directives, "opcache.validate_permission", ZCG(accel_directives).validate_permission); ++ add_assoc_bool(directives, "opcache.validate_root", ZCG(accel_directives).validate_root); + add_assoc_bool(directives, "opcache.inherited_hack", ZCG(accel_directives).inherited_hack); + add_assoc_bool(directives, "opcache.dups_fix", ZCG(accel_directives).ignore_dups); + add_assoc_bool(directives, "opcache.revalidate_path", ZCG(accel_directives).revalidate_path); +-- +2.1.4 + +From a91f3d475ee9a59c38833c683c0bd355338f1564 Mon Sep 17 00:00:00 2001 +From: Dmitry Stogov +Date: Wed, 16 Nov 2016 16:43:57 +0300 +Subject: [PATCH] Fixed ZTS build + +--- + ext/opcache/zend_accelerator_hash.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/ext/opcache/zend_accelerator_hash.c b/ext/opcache/zend_accelerator_hash.c +index 4b8b712..4a16a93 100644 +--- a/ext/opcache/zend_accelerator_hash.c ++++ b/ext/opcache/zend_accelerator_hash.c +@@ -77,6 +77,9 @@ zend_accel_hash_entry* zend_accel_hash_update(zend_accel_hash *accel_hash, char + zend_ulong index; + zend_accel_hash_entry *entry; + zend_accel_hash_entry *indirect_bucket = NULL; ++#ifndef ZEND_WIN32 ++ TSRMLS_FETCH(); ++#endif + + if (indirect) { + indirect_bucket = (zend_accel_hash_entry*)data; +@@ -148,6 +151,9 @@ void* zend_accel_hash_find(zend_accel_hash *accel_hash, char *key, zend_uint key + zend_ulong hash_value; + zend_ulong index; + zend_accel_hash_entry *entry; ++#ifndef ZEND_WIN32 ++ TSRMLS_FETCH(); ++#endif + + hash_value = zend_inline_hash_func(key, key_length); + #ifndef ZEND_WIN32 +@@ -179,6 +185,9 @@ zend_accel_hash_entry* zend_accel_hash_find_entry(zend_accel_hash *accel_hash, c + zend_ulong hash_value; + zend_ulong index; + zend_accel_hash_entry *entry; ++#ifndef ZEND_WIN32 ++ TSRMLS_FETCH(); ++#endif + + hash_value = zend_inline_hash_func(key, key_length); + #ifndef ZEND_WIN32 +@@ -207,6 +216,9 @@ int zend_accel_hash_unlink(zend_accel_hash *accel_hash, char *key, zend_uint key + zend_ulong hash_value; + zend_ulong index; + zend_accel_hash_entry *entry, *last_entry=NULL; ++#ifndef ZEND_WIN32 ++ TSRMLS_FETCH(); ++#endif + + hash_value = zend_inline_hash_func(key, key_length); + #ifndef ZEND_WIN32 +-- +2.1.4 + +From 8202b970777b84d57c590b78f9b6572ef0e0c205 Mon Sep 17 00:00:00 2001 +From: Dmitry Stogov +Date: Wed, 16 Nov 2016 23:01:40 +0300 +Subject: [PATCH] Use full path + +--- + ext/opcache/ZendAccelerator.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c +index c8d2290..9d0d32e8 100644 +--- a/ext/opcache/ZendAccelerator.c ++++ b/ext/opcache/ZendAccelerator.c +@@ -1563,7 +1563,7 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type T + if (EXPECTED(persistent_script != NULL) && + UNEXPECTED(ZCG(accel_directives).validate_permission) && + file_handle->type == ZEND_HANDLE_FILENAME && +- UNEXPECTED(access(file_handle->filename, R_OK) != 0)) { ++ UNEXPECTED(access(persistent_script->full_path, R_OK) != 0)) { + if (type == ZEND_REQUIRE) { + #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO + zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename); +-- +2.1.4 + +From 9849c97b1bdfd7f0a7c499cad4cf601ebd68cc22 Mon Sep 17 00:00:00 2001 +From: Dmitry Stogov +Date: Thu, 17 Nov 2016 01:08:42 +0300 +Subject: [PATCH] Accorate handling of too big inodes of chroot directories + +--- + ext/opcache/ZendAccelerator.c | 20 ++++++++------------ + 1 file changed, 8 insertions(+), 12 deletions(-) + +diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c +index 9d0d32e8..7e8a444 100644 +--- a/ext/opcache/ZendAccelerator.c ++++ b/ext/opcache/ZendAccelerator.c +@@ -2100,18 +2100,14 @@ static void accel_activate(void) + if (stat("/", &buf) != 0) { + ZCG(root_hash) = 0; + } else { +- unsigned long x = buf.st_ino; +- +-#if SIZEOF_LONG == 4 +- x = ((x >> 16) ^ x) * 0x45d9f3b; +- x = ((x >> 16) ^ x) * 0x45d9f3b; +- x = (x >> 16) ^ x; +-#elif SIZEOF_LONG == 8 +- x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9; +- x = (x ^ (x >> 27)) * 0x94d049bb133111eb; +- x = x ^ (x >> 31); +-#endif +- ZCG(root_hash) = x; ++ ZCG(root_hash) = buf.st_ino; ++ if (sizeof(buf.st_ino) > sizeof(ZCG(root_hash))) { ++ if (ZCG(root_hash) != buf.st_ino) { ++ zend_alter_ini_entry("opcache.enable", sizeof("opcache.enable"), "0", 1, ZEND_INI_SYSTEM, ZEND_INI_STAGE_RUNTIME); ++ zend_accel_error(ACCEL_LOG_WARNING, "Can't cache files in chroot() directory with too big inode"); ++ return; ++ } ++ } + } + } else { + ZCG(root_hash) = 0; +-- +2.1.4 + -- cgit