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