fat Tue, 12 Jul 2011 23:00:42 +0000 Revision: http://svn.php.net/viewvc?view=revision&revision=313186
Log: - Implemented FR #55181 (Enhance security by limiting access to user defined extensions) Bug: https://bugs.php.net/55181 (Analyzed) Enhance security by limiting the script extension Changed paths: U php/php-src/branches/PHP_5_4/NEWS U php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_conf.c U php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_conf.h U php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_main.c U php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_php.c U php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_php.h U php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_worker_pool.h U php/php-src/branches/PHP_5_4/sapi/fpm/php-fpm.conf.in
Modified: php/php-src/branches/PHP_5_4/NEWS =================================================================== --- php/php-src/branches/PHP_5_4/NEWS 2011-07-12 22:54:20 UTC (rev 313185) +++ php/php-src/branches/PHP_5_4/NEWS 2011-07-12 23:00:42 UTC (rev 313186) @@ -14,6 +14,8 @@ - Improved PHP-FPM SAPI: . Added partial syslog support (on error_log only). FR #52052. (fat) . Lowered default value for Process Manager. FR #54098. (fat) + . Enhance security by limiting access to user defined extensions. + FR #55181. (fat) - Improved core functions: . Changed http_response_code() to be able to set a response code. (Kalle) Modified: php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_conf.c =================================================================== --- php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_conf.c 2011-07-12 22:54:20 UTC (rev 313185) +++ php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_conf.c 2011-07-12 23:00:42 UTC (rev 313186) @@ -121,6 +121,7 @@ { "ping.response", &fpm_conf_set_string, WPO(ping_response) }, { "access.log", &fpm_conf_set_string, WPO(access_log) }, { "access.format", &fpm_conf_set_string, WPO(access_format) }, + { "security.limit_extensions", &fpm_conf_set_string, WPO(security_limit_extensions) }, { 0, 0, 0 } }; @@ -599,6 +600,7 @@ free(wpc->prefix); free(wpc->access_log); free(wpc->access_format); + free(wpc->security_limit_extensions); return 0; } @@ -845,6 +847,56 @@ } } + if (!wp->config->security_limit_extensions) { + wp->config->security_limit_extensions = strdup(".php"); + } + + if (*wp->config->security_limit_extensions) { + int nb_ext; + char *ext; + char *security_limit_extensions; + char *limit_extensions; + + + /* strdup because strtok(3) alters the string it parses */ + security_limit_extensions = strdup(wp->config->security_limit_extensions); + limit_extensions = security_limit_extensions; + nb_ext = 0; + + /* find the number of extensions */ + while ((ext = strtok(limit_extensions, " \t"))) { + limit_extensions = NULL; + nb_ext++; + } + free(security_limit_extensions); + + /* if something found */ + if (nb_ext > 0) { + + /* malloc the extension array */ + wp->limit_extensions = malloc(sizeof(char *) * (nb_ext + 1)); + if (!wp->limit_extensions) { + zlog(ZLOG_ERROR, "[pool %s] unable to malloc extensions array", wp->config->name); + return -1; + } + + /* strdup because strtok(3) alters the string it parses */ + security_limit_extensions = strdup(wp->config->security_limit_extensions); + limit_extensions = security_limit_extensions; + nb_ext = 0; + + /* parse the string and save the extension in the array */ + while ((ext = strtok(security_limit_extensions, " \t"))) { + security_limit_extensions = NULL; + wp->limit_extensions[nb_ext++] = strdup(ext); + } + + /* end the array with NULL in order to parse it */ + wp->limit_extensions[nb_ext] = NULL; + free(security_limit_extensions); + } + } + if (wp->config->chroot && *wp->config->chroot) { fpm_evaluate_full_path(&wp->config->chroot, wp, NULL, 1); @@ -1380,6 +1432,7 @@ zlog(ZLOG_NOTICE, "\tslowlog = %s", STR2STR(wp->config->slowlog)); zlog(ZLOG_NOTICE, "\trlimit_files = %d", wp->config->rlimit_files); zlog(ZLOG_NOTICE, "\trlimit_core = %d", wp->config->rlimit_core); + zlog(ZLOG_NOTICE, "\tsecurity.limit_extensions = %s", wp->config->security_limit_extensions); for (kv = wp->config->env; kv; kv = kv->next) { zlog(ZLOG_NOTICE, "\tenv[%s] = %s", kv->key, kv->value); Modified: php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_conf.h =================================================================== --- php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_conf.h 2011-07-12 22:54:20 UTC (rev 313185) +++ php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_conf.h 2011-07-12 23:00:42 UTC (rev 313186) @@ -66,6 +66,7 @@ char *listen_group; char *listen_mode; char *listen_allowed_clients; + char *security_limit_extensions; struct key_value_s *env; struct key_value_s *php_admin_values; struct key_value_s *php_values; Modified: php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_main.c =================================================================== --- php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_main.c 2011-07-12 22:54:20 UTC (rev 313185) +++ php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_main.c 2011-07-12 23:00:42 UTC (rev 313186) @@ -1879,6 +1879,12 @@ goto fastcgi_request_done; } + if (fpm_php_limit_extensions(SG(request_info).path_translated)) { + SG(sapi_headers).http_response_code = 403; + PUTS("Access denied.\n"); + goto fastcgi_request_done; + } + /* path_translated exists, we can continue ! */ if (php_fopen_primary_script(&file_handle TSRMLS_CC) == FAILURE) { zend_try { Modified: php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_php.c =================================================================== --- php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_php.c 2011-07-12 22:54:20 UTC (rev 313185) +++ php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_php.c 2011-07-12 23:00:42 UTC (rev 313186) @@ -19,7 +19,10 @@ #include "fpm_php.h" #include "fpm_cleanup.h" #include "fpm_worker_pool.h" +#include "zlog.h" +static char **limit_extensions = NULL; + static int fpm_php_zend_ini_alter_master(char *name, int name_length, char *new_value, int new_value_length, int mode, int stage TSRMLS_DC) /* {{{ */ { zend_ini_entry *ini_entry; @@ -219,7 +222,38 @@ 0 > fpm_php_set_allowed_clients(wp)) { return -1; } + + if (wp->limit_extensions) { + limit_extensions = wp->limit_extensions; + } return 0; } /* }}} */ +int fpm_php_limit_extensions(char *path) /* {{{ */ +{ + char **p; + size_t path_len; + + if (!path || !limit_extensions) { + return 0; /* allowed by default */ + } + + p = limit_extensions; + path_len = strlen(path); + while (p && *p) { + size_t ext_len = strlen(*p); + if (path_len > ext_len) { + char *path_ext = path + path_len - ext_len; + if (strcmp(*p, path_ext) == 0) { + return 0; /* allow as the extension has been found */ + } + } + p++; + } + + + zlog(ZLOG_NOTICE, "Access to the file '%s' has been denied (see security.limit_extensions)", path); + return 1; /* extension not found: not allowed */ +} +/* }}} */ Modified: php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_php.h =================================================================== --- php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_php.h 2011-07-12 22:54:20 UTC (rev 313185) +++ php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_php.h 2011-07-12 23:00:42 UTC (rev 313186) @@ -43,6 +43,7 @@ void fpm_php_soft_quit(); int fpm_php_init_main(); int fpm_php_apply_defines_ex(struct key_value_s *kv, int mode); +int fpm_php_limit_extensions(char *path); #endif Modified: php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_worker_pool.h =================================================================== --- php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_worker_pool.h 2011-07-12 22:54:20 UTC (rev 313185) +++ php/php-src/branches/PHP_5_4/sapi/fpm/fpm/fpm_worker_pool.h 2011-07-12 23:00:42 UTC (rev 313186) @@ -37,6 +37,7 @@ #endif struct fpm_scoreboard_s *scoreboard; int log_fd; + char **limit_extensions; }; struct fpm_worker_pool_s *fpm_worker_pool_alloc(); Modified: php/php-src/branches/PHP_5_4/sapi/fpm/php-fpm.conf.in =================================================================== --- php/php-src/branches/PHP_5_4/sapi/fpm/php-fpm.conf.in 2011-07-12 22:54:20 UTC (rev 313185) +++ php/php-src/branches/PHP_5_4/sapi/fpm/php-fpm.conf.in 2011-07-12 23:00:42 UTC (rev 313186) @@ -421,6 +421,14 @@ ; process time (several ms). ; Default Value: no ;catch_workers_output = yes + +; Limits the extensions of the main script FPM will allow to parse. This can +; prevent configuration mistakes on the web server side. You should only limit +; FPM to .php extensions to prevent malicious users to use other extensions to +; exectute php code. +; Note: set an empty value to allow all extensions. +; Default Value: .php +;security.limit_extensions = .php .php3 .php4 .php5 ; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from ; the current environment.
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php