php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #48677 Terrible performance when open_basedir (of any length) is used
Submitted: 2009-06-24 17:39 UTC Modified: 2009-07-03 01:00 UTC
Votes:3
Avg. Score:4.0 ± 0.8
Reproduced:3 of 3 (100.0%)
Same Version:3 (100.0%)
Same OS:0 (0.0%)
From: rickt at rickt dot org Assigned:
Status: No Feedback Package: Safe Mode/open_basedir
PHP Version: 5.2.10 OS: CentOS 4 update 5
Private report: No CVE-ID: None
 [2009-06-24 17:39 UTC] rickt at rickt dot org
Description:
------------
This is related to bug ID 43946.

I too am seeing terrible performance when using open_basedir. Even when using the various hints/tips about open_basedir (put "." at the end, put most-frequently-used include paths at the beginning of the variable, etc), and despite our best efforts at reducing the number of entries within open_basedir, with only 3 entries (including ".") we see an enormous CPU hit.



Reproduce code:
---------------
A site that with no open_basedir set had an average CPU load of about 90-98% idle with 1-2% in system time. With open_basedir set, CPU load immediately climbs to 0-1% idle, and up to 91+% in system time, as can be seen below via the output from sar:

--- snip ---
07:00:03 PM       CPU     %user     %nice   %system   %iowait     %idle
07:10:04 PM       all      1.41      0.00      1.29      0.47     96.84
07:20:02 PM       all      0.44      0.00      0.69      0.44     98.43
07:30:01 PM       all      3.33      0.00     22.97      0.32     73.37
07:40:05 PM       all      9.83      0.00     74.31      0.09     15.77
07:50:03 PM       all      8.33      0.00     90.48      0.01      1.18
08:00:03 PM       all      7.85      0.00     91.39      0.00      0.75
08:10:05 PM       all      7.67      0.00     90.51      0.08      1.74
08:20:02 PM       all      7.68      0.00     91.65      0.03      0.64
08:30:02 PM       all      7.64      0.00     91.75      0.03      0.58
08:40:02 PM       all      8.24      0.00     90.95      0.06      0.75
08:50:04 PM       all      9.30      0.00     66.71      2.68     21.31
09:00:05 PM       all      9.04      0.00     64.47      0.13     26.36
09:10:01 PM       all      9.13      0.00     64.76      0.14     25.96
09:20:03 PM       all      9.65      0.00     34.30      0.25     55.80
09:30:07 PM       all     10.21      0.00      3.40      0.37     86.01
09:40:02 PM       all      9.66      0.00      3.18      0.39     86.77
09:50:02 PM       all      9.52      0.00      3.16      0.37     86.95
10:00:03 PM       all      9.42      0.00      3.13      0.38     87.07
Average:          all      7.75      0.00     11.53      0.46     80.26
--- snip ---

We added the open_basedir entry (with only 3 folders) at around 07:25 and you can see the massive spike at 07:30:01. Our docroot/code bases are clean and don't have that many includes/requires. We turned off the open_basedir and restarted our fcgis at around 09:25 and the immediate dropoff in load can of course be seen.

Having straced the processes in question, we see enormous amounts of lstat()s and readlink()s etc.

Google reveals some interesting things, specific to the change that occurred in PHP 5.1.5, specific to the php_check_specific_open_basedir() function. I guess that further security-checking code was added to limit the possibility of escaping the open_basedir using symlinks.

Expected result:
----------------
n/a

Actual result:
--------------
n/a

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-06-24 21:09 UTC] rasmus@php.net
But what are these lstats?  Are they the result of a realpath call?  as in something like:

lstat64 /
lstat64 /var
lstat64 /var/www

and at the end of this chain does it result in an ENOENT?  If so, PHP 5.3 will help a bit with this because we have replaced the realpath syscall with our own version which will cache the stats within realpath.  Currently in PHP <5.3 we only cache a successful realpath call, so if you are missing on your include_path there is no cache for the miss and you will see the stats on every request.  It is extremely important that you do not miss.  All includes relative to your script should be: 

include './path/foo.php';

and all include_path includes should be:

include 'path/bar.php';

where your include_path has just '/some/dir' in it and the file would be in /some/dir/path/bar.php

If you do not do it this way and bounce through multiple include_paths in order to find a file, open_basedir is super painful.

If you are doing all this, you could either be overflowing your realpath_cache in which case making it larger might solve it, or alternatively you could be calling clearstatcache() somewhere which will blow away your realpath_cache.  This is also fixed in 5.3 where I added a flag to force a realpath_cache clear from that call, but by default it won't clear it anymore.

Just as a reference, Yahoo has open_basedir enabled on all their servers, and if you understand and follow all of the above, your stats will go away, I guarantee it.
 [2009-07-03 01:00 UTC] php-bugs at lists dot php dot net
No feedback was provided for this bug for over a week, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon Dec 30 14:01:28 2024 UTC