]> granicus.if.org Git - php/commitdiff
Fix bug #78138: opcache.validate_permission incorrectly works with PHAR files
authorAlex Scott <alex@cgi-central.net>
Tue, 11 Jun 2019 14:31:07 +0000 (18:31 +0400)
committerNikita Popov <nikita.ppv@gmail.com>
Tue, 2 Jul 2019 10:25:50 +0000 (12:25 +0200)
opcache incorrectly handles PHAR files when opcache.validate_permission
option enabled, because it calls

  access("phar://path-to/file.phar/path/inside.php", R_OK);

rather than

  access("path-to/file.phar", R_OK)

ext/opcache/ZendAccelerator.c

index b6c001d63712d9f2ae80a8ae4b3992387467dcf8..15629224244884402bba12f2a6e25c3b903ed87d 100644 (file)
@@ -1760,6 +1760,29 @@ zend_op_array *file_cache_compile_file(zend_file_handle *file_handle, int type)
 }
 #endif
 
+int check_persistent_script_access(zend_persistent_script *persistent_script)
+{
+    char *phar_path, *ptr;
+    int ret;
+    if ((ZSTR_LEN(persistent_script->script.filename)<sizeof("phar://.phar")) ||
+         memcmp(ZSTR_VAL(persistent_script->script.filename), "phar://", sizeof("phar://")-1)) {
+
+        return access(ZSTR_VAL(persistent_script->script.filename), R_OK) != 0;
+
+    } else {
+        /* we got a cached file from .phar, so we have to strip prefix and path inside .phar to check access() */
+        phar_path = estrdup(ZSTR_VAL(persistent_script->script.filename)+sizeof("phar://")-1);
+        if ((ptr = strstr(phar_path, ".phar/")) != NULL)
+        {
+            *(ptr+sizeof(".phar/")-2) = 0; /* strip path inside .phar file */
+        }
+        ret = access(phar_path, R_OK) != 0;
+        efree(phar_path);
+        return ret;
+    }
+}
+
+
 /* zend_compile() replacement */
 zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
 {
@@ -1896,7 +1919,7 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
        if (EXPECTED(persistent_script != NULL) &&
            UNEXPECTED(ZCG(accel_directives).validate_permission) &&
            file_handle->type == ZEND_HANDLE_FILENAME &&
-           UNEXPECTED(access(ZSTR_VAL(persistent_script->script.filename), R_OK) != 0)) {
+           UNEXPECTED(check_persistent_script_access(persistent_script))) {
                if (type == ZEND_REQUIRE) {
                        zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
                        zend_bailout();