cvs: php4 / php.ini-dist php.ini-optimized /ext/standard dir.c /main fopen_wrappers.c main.c php_globals.h safe_mode.c safe_mode.h

From: Date: Fri, 13 Jul 2001 18:21:21 +0000
Subject: cvs: php4 / php.ini-dist php.ini-optimized /ext/standard dir.c /main fopen_wrappers.c main.c php_globals.h safe_mode.c safe_mode.h
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-6216@lists.php.net to get a copy of this message
jflemer Fri Jul 13 14:21:21 2001 EDT Modified files: /php4 php.ini-dist php.ini-optimized /php4/ext/standard dir.c /php4/main fopen_wrappers.c main.c php_globals.h safe_mode.c safe_mode.h Log: o Fixed Bug #12121: chdir and safe_mode - [ main/safe_mode.h ] added new checkuid mode: CHECKUID_ALLOW_ONLY_FILE: skips directory check if file check fails - [ ext/standard/dir.c ] changed php_checkuid() to use CHECKUID_ALLOW_ONLY_FILE instead of CHECKUID_ALLOW_ONLY_DIR - [ main/safe_mode.c ] added code for new checkuid mode o Fixed Bug #12119: safe mode owner check can be bypassed with symlink - [ main/safe_mode.c ] use VCWD_REALPATH to resolve destination of symlink before trimming filename o New Feature: safe_mode_include_dir (php.ini directive) - Allows bypassing UID/GID checks when including files from the directory in safe_mode_include_dir and its subdirectories. (safe_mode must be on, directory must also be in include_path or full path must be used when including) o Fixed Feature: safe_mode_gid (php.ini directive) - Correctly check (and report) UID/GID bits on directories o Changed include() fall back to scripts cwd implementation - CWD added to the (local) search path in php_fopen_with_path() instead of seperate case. [ main/fopen_wrappers.c ]

Index: php4/php.ini-dist diff -u php4/php.ini-dist:1.87 php4/php.ini-dist:1.88 --- php4/php.ini-dist:1.87 Mon Jul 9 13:36:03 2001 +++ php4/php.ini-dist Fri Jul 13 14:21:21 2001 @@ -1,5 +1,5 @@ [PHP] -; $Id: php.ini-dist,v 1.87 2001/07/09 17:36:03 rasmus Exp $ +; $Id: php.ini-dist,v 1.88 2001/07/13 18:21:21 jflemer Exp $ ;;;;;;;;;;;;;;;;;;; ; About this file ; @@ -115,6 +115,12 @@ ; opening files. If you want to relax this to a GID compare, ; then turn on safe_mode_gid. safe_mode_gid = Off + +; When safe_mode is on, UID/GID checks are bypassed when +; including files from this directory and its subdirectories. +; (directory must also be in include_path or full path must +; be used when including) +safe_mode_include_dir = ; When safe_mode is on, only executables located in the safe_mode_exec_dir ; will be allowed to be executed via the exec family of functions. Index: php4/php.ini-optimized diff -u php4/php.ini-optimized:1.41 php4/php.ini-optimized:1.42 --- php4/php.ini-optimized:1.41 Mon Jul 9 13:36:03 2001 +++ php4/php.ini-optimized Fri Jul 13 14:21:21 2001 @@ -84,7 +84,12 @@ safe_mode_gid = Off ; By default, Safe Mode does a UID compare ; check when opening files. If you want to ; relax this to a GID compare, then turn on - ; safe_mode_gid. + ; safe_mode_gid. (safe_mode must be On) +safe_mode_include_dir = ; When safe_mode is on, UID/GID checks are + ; bypassed when including files from this + ; directory and its subdirectories. (directory + ; must also be in include_path or full path + ; must be used when including) safe_mode_exec_dir = safe_mode_allowed_env_vars = PHP_ ; Setting certain environment variables ; may be a potential security breach. @@ -532,4 +537,4 @@ ; Local Variables: ; tab-width: 4 -; End: \ No newline at end of file +; End: Index: php4/ext/standard/dir.c diff -u php4/ext/standard/dir.c:1.69 php4/ext/standard/dir.c:1.70 --- php4/ext/standard/dir.c:1.69 Wed Jun 20 11:46:47 2001 +++ php4/ext/standard/dir.c Fri Jul 13 14:21:21 2001 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: dir.c,v 1.69 2001/06/20 15:46:47 thies Exp $ */ +/* $Id: dir.c,v 1.70 2001/07/13 18:21:21 jflemer Exp $ */ /* {{{ includes/startup/misc */ @@ -282,7 +282,7 @@ } convert_to_string_ex(arg); - if (PG(safe_mode) && !php_checkuid((*arg)->value.str.val, NULL, CHECKUID_ALLOW_ONLY_DIR)) { + if (PG(safe_mode) && !php_checkuid((*arg)->value.str.val, NULL, CHECKUID_ALLOW_ONLY_FILE)) { RETURN_FALSE; } ret = VCWD_CHDIR((*arg)->value.str.val); Index: php4/main/fopen_wrappers.c diff -u php4/main/fopen_wrappers.c:1.121 php4/main/fopen_wrappers.c:1.122 --- php4/main/fopen_wrappers.c:1.121 Wed Jul 11 13:10:13 2001 +++ php4/main/fopen_wrappers.c Fri Jul 13 14:21:21 2001 @@ -16,7 +16,7 @@ | Jim Winstead <jimw@php.net> | +----------------------------------------------------------------------+ */ -/* $Id: fopen_wrappers.c,v 1.121 2001/07/11 17:10:13 zeev Exp $ */ +/* $Id: fopen_wrappers.c,v 1.122 2001/07/13 18:21:21 jflemer Exp $ */ /* {{{ includes */ @@ -389,20 +389,64 @@ PHPAPI FILE *php_fopen_with_path(char *filename, char *mode, char *path, char **opened_path) { char *pathbuf, *ptr, *end; + char *exec_fname; char trypath[MAXPATHLEN]; + char trydir[MAXPATHLEN]; + char safe_mode_include_dir[MAXPATHLEN]; struct stat sb; FILE *fp; + int path_length; int filename_length; + int safe_mode_include_dir_length; + int exec_fname_length; PLS_FETCH(); + ELS_FETCH(); if (opened_path) { *opened_path = NULL; } + + if(!filename) { + return NULL; + } filename_length = strlen(filename); - - /* Absolute & relative path open */ - if ((*filename == '.') || (IS_ABSOLUTE_PATH(filename, filename_length))) { + + /* Relative path open */ + if (*filename == '.') { + if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) { + return NULL; + } + return php_fopen_and_set_opened_path(filename, mode, opened_path); + } + + /* + * files in safe_mode_include_dir (or subdir) are excluded from + * safe mode GID/UID checks + */ + *safe_mode_include_dir = 0; + safe_mode_include_dir_length = 0; + if(PG(safe_mode_include_dir) && VCWD_REALPATH(PG(safe_mode_include_dir), safe_mode_include_dir)) { + safe_mode_include_dir_length = strlen(safe_mode_include_dir); + } + + /* Absolute path open */ + if (IS_ABSOLUTE_PATH(filename, filename_length)) { + /* Check to see if file is in safe_mode_include_dir (or subdir) */ + if (PG(safe_mode) && *safe_mode_include_dir && VCWD_REALPATH(filename, trypath)) { +#ifdef PHP_WIN32 + if (strncasecmp(safe_mode_include_dir, trypath, safe_mode_include_dir_length) == 0) +#else + if (strncmp(safe_mode_include_dir, trypath, safe_mode_include_dir_length) == 0) +#endif + { + /* absolute path matches safe_mode_include_dir */ + fp = php_fopen_and_set_opened_path(trypath, mode, opened_path); + if (fp) { + return fp; + } + } + } if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) { return NULL; } @@ -415,7 +459,31 @@ } return php_fopen_and_set_opened_path(filename, mode, opened_path); } - pathbuf = estrdup(path); + + /* check in provided path */ + /* append the calling scripts' current working directory + * as a fall back case + */ + exec_fname = zend_get_executed_filename(ELS_C); + exec_fname_length = strlen(exec_fname); + path_length = strlen(path); + + while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length])) { + } + if (exec_fname && exec_fname[0] == '[') { + /* [no active file] */ + exec_fname_length = 0; + } + + pathbuf = (char *) emalloc(exec_fname_length + path_length +1 +1); + memcpy(pathbuf, path, path_length); +#ifdef PHP_WIN32 + pathbuf[path_length] = ';'; +#else + pathbuf[path_length] = ':'; +#endif + memcpy(pathbuf+path_length+1, exec_fname, exec_fname_length); + pathbuf[path_length + exec_fname_length +1] = '\0'; ptr = pathbuf; @@ -430,6 +498,22 @@ end++; } snprintf(trypath, MAXPATHLEN, "%s/%s", ptr, filename); + /* Check to see trypath is in safe_mode_include_dir (or subdir) */ + if (PG(safe_mode) && *safe_mode_include_dir && VCWD_REALPATH(trypath, trydir)) { +#ifdef PHP_WIN32 + if (strncasecmp(safe_mode_include_dir, trydir, safe_mode_include_dir_length) == 0) +#else + if (strncmp(safe_mode_include_dir, trydir, safe_mode_include_dir_length) == 0) +#endif + { + /* trypath is in safe_mode_include_dir */ + fp = php_fopen_and_set_opened_path(trydir, mode, opened_path); + if (fp) { + efree(pathbuf); + return fp; + } + } + } if (PG(safe_mode)) { if (VCWD_STAT(trypath, &sb) == 0 && (!php_checkuid(trypath, mode, CHECKUID_CHECK_MODE_PARAM))) { efree(pathbuf); @@ -442,37 +526,10 @@ return fp; } ptr = end; - } + } /* end provided path */ efree(pathbuf); - - { - char *exec_fname; - int exec_fname_len; - ELS_FETCH(); - - exec_fname = zend_get_executed_filename(ELS_C); - exec_fname_len = strlen(exec_fname); - - pathbuf = (char *) emalloc(exec_fname_len+filename_length+1+1); /* Over allocate to save time */ - memcpy(pathbuf, exec_fname, exec_fname_len+1); - - while ((--exec_fname_len >= 0) && !IS_SLASH(pathbuf[exec_fname_len])) { - } - pathbuf[exec_fname_len] = DEFAULT_SLASH; - memcpy(&pathbuf[exec_fname_len+1], filename, filename_length+1); - - if (PG(safe_mode)) { - if (VCWD_STAT(pathbuf, &sb) == 0 && (!php_checkuid(pathbuf, mode, CHECKUID_CHECK_MODE_PARAM))) { - efree(pathbuf); - return NULL; - } - } - fp = php_fopen_and_set_opened_path(pathbuf, mode, opened_path); - efree(pathbuf); - return fp; - } - return NULL; /* Not really needed anymore */ + return NULL; } /* }}} */ Index: php4/main/main.c diff -u php4/main/main.c:1.374 php4/main/main.c:1.375 --- php4/main/main.c:1.374 Fri Jul 13 12:08:38 2001 +++ php4/main/main.c Fri Jul 13 14:21:21 2001 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: main.c,v 1.374 2001/07/13 16:08:38 sas Exp $ */ +/* $Id: main.c,v 1.375 2001/07/13 18:21:21 jflemer Exp $ */ /* {{{ includes */ @@ -215,6 +215,7 @@ STD_PHP_INI_BOOLEAN("register_argc_argv", "1", PHP_INI_ALL, OnUpdateBool, register_argc_argv, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("register_globals", "1", PHP_INI_ALL, OnUpdateBool, register_globals, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("safe_mode", "0", PHP_INI_SYSTEM, OnUpdateBool, safe_mode, php_core_globals, core_globals) + STD_PHP_INI_ENTRY("safe_mode_include_dir", NULL, PHP_INI_SYSTEM, OnUpdateString, safe_mode_include_dir, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("safe_mode_gid", "0", PHP_INI_SYSTEM, OnUpdateBool, safe_mode_gid, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("short_open_tag",DEFAULT_SHORT_OPEN_TAG, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, short_tags, zend_compiler_globals, compiler_globals) STD_PHP_INI_BOOLEAN("sql.safe_mode", "0", PHP_INI_SYSTEM, OnUpdateBool, sql_safe_mode, php_core_globals, core_globals) Index: php4/main/php_globals.h diff -u php4/main/php_globals.h:1.66 php4/main/php_globals.h:1.67 --- php4/main/php_globals.h:1.66 Fri Jul 13 12:08:39 2001 +++ php4/main/php_globals.h Fri Jul 13 14:21:21 2001 @@ -68,6 +68,7 @@ zend_bool implicit_flush; zend_bool safe_mode; + char *safe_mode_include_dir; zend_bool safe_mode_gid; zend_bool sql_safe_mode; zend_bool enable_dl; Index: php4/main/safe_mode.c diff -u php4/main/safe_mode.c:1.32 php4/main/safe_mode.c:1.33 --- php4/main/safe_mode.c:1.32 Mon Jul 9 14:57:19 2001 +++ php4/main/safe_mode.c Fri Jul 13 14:21:21 2001 @@ -15,7 +15,7 @@ | Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca> | +----------------------------------------------------------------------+ */ -/* $Id: safe_mode.c,v 1.32 2001/07/09 18:57:19 rasmus Exp $ */ +/* $Id: safe_mode.c,v 1.33 2001/07/13 18:21:21 jflemer Exp $ */ #include "php.h" @@ -48,6 +48,7 @@ struct stat sb; int ret; long uid=0L, gid=0L, duid=0L, dgid=0L; + char path[MAXPATHLEN]; char *s; PLS_FETCH(); @@ -71,8 +72,12 @@ return 1; } + /* First we see if the file is owned by the same user... + * If that fails, passthrough and check directory... + */ if (mode != CHECKUID_ALLOW_ONLY_DIR) { - ret = VCWD_STAT(filename, &sb); + VCWD_REALPATH(filename, path); + ret = VCWD_STAT(path, &sb); if (ret < 0) { if (mode == CHECKUID_DISALLOW_FILE_NOT_EXISTS) { php_error(E_WARNING, "Unable to access %s", filename); @@ -83,63 +88,67 @@ } } else { uid = sb.st_uid; + gid = sb.st_gid; if (uid == php_getuid()) { return 1; + } else if (PG(safe_mode_gid) && gid == php_getgid()) { + return 1; } } - } - s = strrchr(filename,'/'); - - /* This loop gets rid of trailing slashes which could otherwise be - * used to confuse the function. - */ - while(s && *(s+1)=='\0' && s>filename) { - *s='\0'; - s = strrchr(filename,'/'); - } - if (s) { - *s='\0'; - ret = VCWD_STAT(filename, &sb); - *s='/'; + /* Trim off filename */ + if (s = strrchr(path,DEFAULT_SLASH)) { + *s = '\0'; + } + } else { /* CHECKUID_ALLOW_ONLY_DIR */ + s = strrchr(filename,DEFAULT_SLASH); + + if (s) { + *s = '\0'; + VCWD_REALPATH(filename, path); + *s = DEFAULT_SLASH; + } else { + VCWD_GETCWD(path, MAXPATHLEN); + } + } /* end CHECKUID_ALLOW_ONLY_DIR */ + + if (mode != CHECKUID_ALLOW_ONLY_FILE) { + /* check directory */ + ret = VCWD_STAT(path, &sb); if (ret < 0) { php_error(E_WARNING, "Unable to access %s", filename); return 0; } duid = sb.st_uid; - } else { - char cwd[MAXPATHLEN]; - if (!VCWD_GETCWD(cwd, MAXPATHLEN)) { - php_error(E_WARNING, "Unable to access current working directory"); - return 0; - } - ret = VCWD_STAT(cwd, &sb); - if (ret < 0) { - php_error(E_WARNING, "Unable to access %s", cwd); - return 0; - } - duid = sb.st_uid; - } - if (duid == (uid=php_getuid())) { - return 1; - } else if (PG(safe_mode_gid) && dgid == (gid=php_getgid())) { - return 1; - } else { - SLS_FETCH(); + dgid = sb.st_gid; + if (duid == php_getuid()) { + return 1; + } else if (PG(safe_mode_gid) && dgid == php_getgid()) { + return 1; + } else { + SLS_FETCH(); - if (SG(rfc1867_uploaded_files)) { - if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, strlen(filename)+1)) { - return 1; + if (SG(rfc1867_uploaded_files)) { + if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, strlen(filename)+1)) { + return 1; + } } } + } - if (PG(safe_mode_gid)) { - php_error(E_WARNING, "SAFE MODE Restriction in effect. The script whose uid/gid is %ld/%ld is not allowed to access %s owned by uid/gid %ld/%ld", uid, gid, filename, duid, dgid); - } else { - php_error(E_WARNING, "SAFE MODE Restriction in effect. The script whose uid is %ld is not allowed to access %s owned by uid %ld", uid, filename, duid); - } - return 0; + if (mode == CHECKUID_ALLOW_ONLY_DIR) { + uid = duid; + gid = dgid; + if (s) { + *s = 0; + } } + if (PG(safe_mode_gid)) { + php_error(E_WARNING, "SAFE MODE Restriction in effect. The script whose uid/gid is %ld/%ld is not allowed to access %s owned by uid/gid %ld/%ld", php_getuid(), php_getgid(), filename, uid, gid); + } else { + php_error(E_WARNING, "SAFE MODE Restriction in effect. The script whose uid is %ld is not allowed to access %s owned by uid %ld", php_getuid(), filename, uid); + } + return 0; } Index: php4/main/safe_mode.h diff -u php4/main/safe_mode.h:1.6 php4/main/safe_mode.h:1.7 --- php4/main/safe_mode.h:1.6 Thu Nov 2 18:30:48 2000 +++ php4/main/safe_mode.h Fri Jul 13 14:21:21 2001 @@ -7,6 +7,7 @@ #define CHECKUID_CHECK_FILE_AND_DIR 2 #define CHECKUID_ALLOW_ONLY_DIR 3 #define CHECKUID_CHECK_MODE_PARAM 4 +#define CHECKUID_ALLOW_ONLY_FILE 5 extern PHPAPI int php_checkuid(const char *filename, char *fopen_mode, int mode); extern PHPAPI char *php_get_current_user(void);
« previous php.cvs (#6216) next »