Edit report at https://bugs.php.net/bug.php?id=52312&edit=1
ID: 52312
Comment by: Terry at ellisons dot org dot uk
Reported by: v dot damore at gmail dot com
Summary: PHP safe_mode/open_basedir - lstat performance
problem
Status: Analyzed
Type: Bug
Package: Safe Mode/open_basedir
Operating System: Linux
PHP Version: 5.2.13
Block user comment: N
Private report: N
New Comment:
Incidentally I've just straced opening a require_once on
/home/terry/work/ext/lpc/tests/dd2.inc
and PHP 5.3.17 does the 7 x lstat walk that you indicate is necessary to meet
CVE-2006-5178, but it then repeats this another 5 times and does another 3
fstats after the file is opened 45 f/lstats all in 2.5μS (on a local disk
clearly).
PHP 5.4.6 is worse, it does 5x7 walks, opens the file then does 4 fstatsand
reads the file, before doing another 3x7 lstat walks and a last stat for luck,
giving a grand total of 60 f/lstats in 4μS though this one includes mmapping
the contents from the file cache.
OK, I can understand -- though question -- mandating one walk but why do it
seven times ????
Previous Comments:
------------------------------------------------------------------------
[2013-02-23 00:08:51] Terry at ellisons dot org dot uk
For the purposes of this bug, let's document the advisory which triggered this
change: CVE-2006-5178 see
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2006-5178.
Let's be honest, even with this patch there is still a minuscule chance that
the exploit described could succeed, because we can't go into kernel mode
during the recursive descent and prevent other processes with a higher nice
being scheduled in and doing the dirty. So it replaces "very small" by "even
smaller" at the same time killing NFS performance.
As I said don't remove this change, just make it elective by adding an extra
variant of the open_basedir parameter, and openly documenting the issues so
that sysadmins can make their own judgement call on security vs performance.
Let's face it on a typical shared service I can think of easier ways to do this
exploit. E.g. if exec and the proc functions aren't disabled then there is no
point in having a strong open_basedir. If you are an enterprise and just want
to lock down your apps programmers from breaching good practice /
infrastructure standards over a NAS infrastructure then the weak form is
perfectly appropriate.
Also IMO, PHP is trying to do a better job here than the standard Linux
realpath function and failing.
------------------------------------------------------------------------
[2013-02-22 23:26:14] [email protected]
There is no such thing as a "miniscule race" when it comes to computers. Either
there is a race condition or there isn't. In this case there is. So if we
remove
this check open_basedir will be much less secure. Something along the lines of
Marcin's idea of separate caches might be feasible, but this is not a small
change.
------------------------------------------------------------------------
[2013-02-22 23:17:59] Terry at ellisons dot org dot uk
This bug is extant in 5.3 and 5.4 (up to 5.4.9). The flaw is the logic in
main/main.c:php_module_startup():
/* Disable realpath cache if safe_mode or open_basedir are set */
if (PG(safe_mode) || (PG(open_basedir) && *PG(open_basedir))) {
CWDG(realpath_cache_size_limit) = 0;
}
Similar logic validly exists in code such as suEXEC and suPHP to prevent a race
condition allowing and unscrupulous script author to execute a script in
another UID in certain circumstances. This simply doesn't apply in this case.
Which technically a similar race could allow a script author to break the
basedir contain with miniscule probability by exploiting such a race, the
performance impacts are significant, for no material increase in security
strength. Get rid of this rule or at least split open_basedir into two
separate directives open_basedir_paranoid which disables the cache as above and
open_basedir which does the rational checks and doesn't disable the cache.
This has been lying around for nearly 3 years. How can we progress this?
------------------------------------------------------------------------
[2012-07-31 20:00:48] marcin at 6irc dot net
How about having concurrent cache tables for each basedir setting? For
instance, when open_basedir is set to '/home/teh1234;/tmp', then the lstat
populates only cache table "0", realpath_cache_* also uses exclusively this
cache, and when open_basedir is set to '/home/klaczy;/tmp' then it populates
and uses only cache table "1"? Are there any security considerations that I
don't notice here?
------------------------------------------------------------------------
[2011-08-16 18:52:34] spam2 at rhsoft dot net
> Caching open_basedir stats is insecure
not really because the permissions are not changed the whole day
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=52312
--
Edit this bug report at https://bugs.php.net/bug.php?id=52312&edit=1