Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:17163 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 77267 invoked by uid 1010); 7 Jul 2005 11:45:30 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 77252 invoked from network); 7 Jul 2005 11:45:30 -0000 Received: from unknown (HELO lenivec.com) (127.0.0.1) by localhost with SMTP; 7 Jul 2005 11:45:30 -0000 Received: from ([127.0.0.1:1534]) by pb1.pair.com (ecelerity 1.2 r(5656M)) with ECSTREAM id 96/92-05285-AD51DC24 for ; Thu, 07 Jul 2005 07:45:30 -0400 X-Host-Fingerprint: 212.18.63.135 mail.domenca.com Linux 2.4 w/o timestamps Received: from ([212.18.63.135:56913] helo=condor.domenca.com) by pb1.pair.com (ecelerity 1.2 r(5656M)) with SMTP id 78/42-05285-D421DC24 for ; Thu, 07 Jul 2005 07:30:22 -0400 Received: from bostjan.inkubator.loc (BSN-77-158-60.dsl.siol.net [193.77.158.60]) (authenticated bits=0) by condor.domenca.com (8.12.11/8.12.11) with ESMTP id j67BUGc2009431 (version=TLSv1/SSLv3 cipher=RC4-MD5 bits=128 verify=NO) for ; Thu, 7 Jul 2005 13:30:17 +0200 To: internals@lists.php.net Date: Thu, 7 Jul 2005 13:30:16 +0200 User-Agent: KMail/1.6.2 MIME-Version: 1.0 Content-Disposition: inline Content-Type: Multipart/Mixed; boundary="Boundary-00=_IJRzC5rbDv9mdBE" Message-ID: <200507071330.16089.spmhere1@lenivec.com> X-SMTP-Server-Signature: condor.domenca.com X-Scanned-By: MIMEDefang 2.42 Subject: Safemode subdirectory workaround From: spmhere1@lenivec.com (Bostjan Skufca) --Boundary-00=_IJRzC5rbDv9mdBE Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Content-Disposition: inline Hello, I created a patch to allow subdirectories to be created and used when safemode is enabled. Please let me demonstrate the approach I took to comment it (implementation also). We have the following file/dir structure: /script.php (owned by sUID) /parent_directory/ (owned by sUID, perm=777) /parent_directory/child_directory/ (owned by rUID) /parent_directory/child_directory/file.txt (owned by rUID) sUID stands for "scriptUID" (the UID of user owning the script) rUID stands for "runningUID" (the UID of user executing the script) Safemode by design works like this: 1. script.php is executed and it want's to access "/parent_directory/child_directory/file.txt" for reading or inclusion; 2. PHP first checks if file.txt owner is the same as sUID - if condition is met access is granted; 3. if first condition is not met PHP continues and checks if "/parent_directory/child_directory/" owner (directory which file.txt resides in) is the same as sUID - if condition is met access is granted 4. If both conditions fail then access is denied and PHP issues an error The idea for modification is quite simple and it extends third statement: 3. if "child_directory/" owner UID is not the same as sUID *but* it is the same as rUID, recursively check parent directories until directory with different owner UID is found or only root directory is left to check Then PHP checks directories towards root and when different UID than rUID is found it has 2 options: 1. if it is the same as sUID access is granted 2. if it is not the same as sUID then access is denied. The concept / idea behind is that if running user (rUID) is able to write into directory owned by himself he had to create that directory. And to create that directory he had to had a permission to do so. I also attached a patch for evaluation but please do not think I consider it good - I am not a C programmer - though it works (at least it seems so)... Best regards, Bostjan --Boundary-00=_IJRzC5rbDv9mdBE Content-Type: text/x-diff; charset="utf-8"; name="php-4.3.10-safemode2.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="php-4.3.10-safemode2.patch" --- php-4.3.10/main/safe_mode.c.orig 2005-02-09 15:40:53.000000000 +0100 +++ php-4.3.10/main/safe_mode.c 2005-02-09 15:46:45.000000000 +0100 @@ -50,6 +50,8 @@ PHPAPI int php_checkuid_ex(const char *f int ret, nofile=0; long uid=0L, gid=0L, duid=0L, dgid=0L; char path[MAXPATHLEN]; + char path_bak[MAXPATHLEN]; + char *s_bak; char *s, filenamecopy[MAXPATHLEN]; php_stream_wrapper *wrapper = NULL; TSRMLS_FETCH(); @@ -137,27 +139,46 @@ PHPAPI int php_checkuid_ex(const char *f } /* end CHECKUID_ALLOW_ONLY_DIR */ if (mode != CHECKUID_ALLOW_ONLY_FILE) { - /* check directory */ - ret = VCWD_STAT(path, &sb); - if (ret < 0) { - if ((flags & CHECKUID_NO_ERRORS) == 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to access %s", filename); + strcpy(path_bak, path); + while (!((path[0] == DEFAULT_SLASH) && (path[1] == '\0')) || (path[0] == '\0')) { + /* check directory */ + ret = VCWD_STAT(path, &sb); + if (ret < 0) { + if ((flags & CHECKUID_NO_ERRORS) == 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to access %s", filename); + } + return 0; + } + duid = sb.st_uid; + dgid = sb.st_gid; + if (duid == php_getuid()) { + return 1; + } else if (PG(safe_mode_gid) && dgid == php_getgid()) { + return 1; + } else if ((duid == getuid()) || (PG(safe_mode_gid) && dgid == getgid())) { + // ok, cycle again + } else { + goto while_end; } - return 0; - } - duid = sb.st_uid; - dgid = sb.st_gid; - if (duid == php_getuid()) { - return 1; - } else if (PG(safe_mode_gid) && dgid == php_getgid()) { - return 1; - } else { - TSRMLS_FETCH(); - if (SG(rfc1867_uploaded_files)) { - if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, strlen(filename)+1)) { - return 1; - } + if (s_bak = strrchr(path, DEFAULT_SLASH)) { + if (s_bak == path) { + goto while_end; + } else { + *s_bak = '\0'; + } + } else { + goto while_end; + } + } // while ($path != '') +while_end: + strcpy(path, path_bak); + + TSRMLS_FETCH(); + + if (SG(rfc1867_uploaded_files)) { + if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, strlen(filename)+1)) { + return 1; } } } --Boundary-00=_IJRzC5rbDv9mdBE--