]> granicus.if.org Git - php/commitdiff
Execute preload script under user defined by opcache.preload_user directive
authorDmitry Stogov <dmitry@zend.com>
Tue, 3 Sep 2019 11:23:13 +0000 (14:23 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 3 Sep 2019 11:23:13 +0000 (14:23 +0300)
ext/opcache/ZendAccelerator.c
ext/opcache/ZendAccelerator.h
ext/opcache/zend_accelerator_module.c

index 6dcf4e43defe154f883381a89113a24119760327..311676a265d29ee0959a5a2c18d000806df7f63b 100644 (file)
@@ -73,7 +73,10 @@ typedef int gid_t;
 
 #ifndef ZEND_WIN32
 # include <sys/types.h>
+# include <sys/wait.h>
 # include <sys/ipc.h>
+# include <pwd.h>
+# include <grp.h>
 #endif
 
 #include <sys/stat.h>
@@ -4478,6 +4481,9 @@ static int accel_finish_startup(void)
        }
 
        if (ZCG(accel_directives).preload && *ZCG(accel_directives).preload) {
+#ifndef ZEND_WIN32
+               int in_child = 0;
+#endif
                int ret = SUCCESS;
                int rc;
                int orig_error_reporting;
@@ -4510,6 +4516,67 @@ static int accel_finish_startup(void)
                        return SUCCESS;
                }
 
+#ifndef ZEND_WIN32
+               if (geteuid() == 0) {
+                       pid_t pid;
+                       struct passwd *pw;
+
+                       if (!ZCG(accel_directives).preload_user
+                        || !*ZCG(accel_directives).preload_user) {
+                               zend_shared_alloc_unlock();
+                               zend_accel_error(ACCEL_LOG_FATAL, "\"opcache.preload_user\" has not been defined");
+                               return FAILURE;
+                       }
+
+                       pw = getpwnam(ZCG(accel_directives).preload_user);
+                       if (pw == NULL) {
+                               zend_shared_alloc_unlock();
+                               zend_accel_error(ACCEL_LOG_FATAL, "Preloading failed to getpwnam(\"%s\")", ZCG(accel_directives).preload_user);
+                               return FAILURE;
+                       }
+
+                       pid = fork();
+                       if (pid == -1) {
+                               zend_shared_alloc_unlock();
+                               zend_accel_error(ACCEL_LOG_FATAL, "Preloading failed to fork()");
+                               return FAILURE;
+                       } else if (pid == 0) { /* children */
+                               if (setgid(pw->pw_gid) < 0) {
+                                       zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setgid(%d)", pw->pw_gid);
+                                       exit(1);
+                               }
+                               if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
+                                       zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to initgroups(\"%s\", %d)", pw->pw_name, pw->pw_uid);
+                                       exit(1);
+                               }
+                               if (setuid(pw->pw_uid) < 0) {
+                                       zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setuid(%d)", pw->pw_uid);
+                                       exit(1);
+                               }
+                               in_child = 1;
+                       } else { /* parent */
+                               int status;
+
+                               if (waitpid(pid, &status, 0) < 0) {
+                                       zend_shared_alloc_unlock();
+                                       zend_accel_error(ACCEL_LOG_FATAL, "Preloading failed to waitpid(%d)", pid);
+                                       return FAILURE;
+                               }
+                               zend_shared_alloc_unlock();
+                               if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+                                       return SUCCESS;
+                               } else {
+                                       return FAILURE;
+                               }
+                       }
+               } else {
+                       if (ZCG(accel_directives).preload_user
+                        && *ZCG(accel_directives).preload_user) {
+                               zend_accel_error(ACCEL_LOG_WARNING, "\"opcache.preload_user\" is ignored");
+                       }
+               }
+#endif
+
                sapi_module.activate = NULL;
                sapi_module.deactivate = NULL;
                sapi_module.register_server_variables = NULL;
@@ -4585,6 +4652,16 @@ static int accel_finish_startup(void)
 
                sapi_activate();
 
+#ifndef ZEND_WIN32
+               if (in_child) {
+                       if (ret == SUCCESS) {
+                               exit(0);
+                       } else {
+                               exit(2);
+                       }
+               }
+#endif
+
                return ret;
        }
 
index 20ac84583dad47108d96f49f38d77a9c4eacbd41..c2f95d7c41c8550c0f93af6df7fc1c25ddbaf843 100644 (file)
@@ -185,6 +185,9 @@ typedef struct _zend_accel_directives {
        zend_bool      huge_code_pages;
 #endif
        char *preload;
+#ifndef ZEND_WIN32
+       char *preload_user;
+#endif
 #ifdef ZEND_WIN32
        char *cache_id;
 #endif
index 25f3cc5b81a9f1b3534061f905bc0eb5372b336d..eb5b1c7537f3fd24c581cf35c26509177b85773c 100644 (file)
@@ -321,6 +321,9 @@ ZEND_INI_BEGIN()
        STD_PHP_INI_BOOLEAN("opcache.huge_code_pages"             , "0"   , PHP_INI_SYSTEM, OnUpdateBool,      accel_directives.huge_code_pages,               zend_accel_globals, accel_globals)
 #endif
        STD_PHP_INI_ENTRY("opcache.preload"                       , ""    , PHP_INI_SYSTEM, OnUpdateStringUnempty,    accel_directives.preload,                zend_accel_globals, accel_globals)
+#ifndef ZEND_WIN32
+       STD_PHP_INI_ENTRY("opcache.preload_user"                  , ""    , PHP_INI_SYSTEM, OnUpdateStringUnempty,    accel_directives.preload_user,           zend_accel_globals, accel_globals)
+#endif
 #if ZEND_WIN32
        STD_PHP_INI_ENTRY("opcache.cache_id"                      , ""    , PHP_INI_SYSTEM, OnUpdateString,           accel_directives.cache_id,               zend_accel_globals, accel_globals)
 #endif
@@ -771,6 +774,9 @@ static ZEND_FUNCTION(opcache_get_configuration)
        add_assoc_bool(&directives,   "opcache.huge_code_pages",         ZCG(accel_directives).huge_code_pages);
 #endif
        add_assoc_string(&directives, "opcache.preload", STRING_NOT_NULL(ZCG(accel_directives).preload));
+#ifndef ZEND_WIN32
+       add_assoc_string(&directives, "opcache.preload_user", STRING_NOT_NULL(ZCG(accel_directives).preload_user));
+#endif
 #if ZEND_WIN32
        add_assoc_string(&directives, "opcache.cache_id", STRING_NOT_NULL(ZCG(accel_directives).cache_id));
 #endif