]> granicus.if.org Git - php/commitdiff
Fixed bug #69090 (check cached files permissions)
authorDmitry Stogov <dmitry@zend.com>
Wed, 16 Nov 2016 09:43:10 +0000 (12:43 +0300)
committerDmitry Stogov <dmitry@zend.com>
Wed, 16 Nov 2016 09:43:10 +0000 (12:43 +0300)
NEWS
ext/opcache/README
ext/opcache/ZendAccelerator.c
ext/opcache/ZendAccelerator.h
ext/opcache/zend_accelerator_hash.c
ext/opcache/zend_accelerator_module.c

diff --git a/NEWS b/NEWS
index bb32f6a3b6e48130d9650a14d65088ab756ea824..9a2f915c1f901fd24dce2f07914a623512f52a84 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,7 @@ PHP                                                                        NEWS
 - Opcache:
   . Fixed bug #73402 (Opcache segfault when using class constant to call a
     method). (Laruence)
+  . Fixed bug #69090 (check cached files permissions)
 
 - OpenSSL
   . Fixed bug #72776 (Invalid parameter in memcpy function trough
index 693a7b4e3cc0a2a58e74130d0c0a8f37f6fdbbe2..d5513c51cea1559ae6016d825c58e31178517fea 100644 (file)
@@ -102,6 +102,16 @@ opcache.validate_timestamps (default "1")
        The frequency of the check is controlled by the directive
        "opcache.revalidate_freq".
 
+opcache.validate_permission (default "0")
+       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_root (default "0")
+       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.revalidate_freq (default "2")
        How often (in seconds) to check file timestamps for changes to the shared
        memory storage allocation. ("1" means validate once per second, but only
index 985a4efac08e1d3f49fcd91a4de9d325472bfb12..c8d22905746f5ef6b45349963727ac55aba14877 100644 (file)
@@ -1592,6 +1592,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 */
@@ -2126,6 +2148,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);
index 11942f10877bdb21824e2716168e32df8f3b3d29..a711de74be5edbf08225a66fa2a60c952d235474 100644 (file)
@@ -230,6 +230,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;
@@ -264,6 +266,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 */
index 992885f59a81528cfe6641b4ba9bc91f6bf08155..4b8b7129ee54b70085b5b1de390e0b1e6a3e48dd 100644 (file)
@@ -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];
index 5671f2f58840109ab8508a1f70fa18da529fec1b..0faa91500f2493f837075de8471308344cc15c84 100644 (file)
@@ -255,6 +255,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)
@@ -663,6 +665,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);