php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #67481 Opcache uses wrong file from cache
Submitted: 2014-06-19 16:02 UTC Modified: 2015-01-01 22:11 UTC
Votes:14
Avg. Score:4.9 ± 0.3
Reproduced:14 of 14 (100.0%)
Same Version:2 (14.3%)
Same OS:4 (28.6%)
From: Danack at basereality dot com Assigned:
Status: Closed Package: opcache
PHP Version: 5.5.13 OS: Centos
Private report: No CVE-ID:
 [2014-06-19 16:02 UTC] Danack at basereality dot com
Description:
------------
When the config 'opcache.validate_timestamps' is set to 0 opcache incorrectly resolves relative filenames.


If you include a file with `require "../src/bootstrap.php";` from two completely different directories then OPcache will serve the same file even though `realpath("../src/bootstrap.php");` resolves to completely different directories.

This does not happen when opcache.validate_timestamps is set to a non-zero value.

It can also be worked around by using `require __DIR__ . '/../src/bootstrap.php';`

Test script:
---------------
File /home/project1/web/index.php
=================================
<?php
require "../src/bootstrap.php";

?>


File /home/project2/web/index.php
=================================
<?php
require "../src/bootstrap.php";

?>

File /home/project2/src/bootstrap.php
=====================================

<?php

echo "I am project2's bootstrap file.";



If you go to a webpage served by project1 first, then go to a webpage served by project2, project2 will get be given project1's bootstrap file.



Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2014-06-19 17:43 UTC] Danack at basereality dot com
-Summary: Opcache +Summary: Opcache uses wrong file from cache
 [2014-06-19 17:43 UTC] Danack at basereality dot com
Made summary not be one word.
 [2014-08-09 03:59 UTC] wojjie at gmail dot com
Same problem exists if you are in a chroot environment. Consider the example provided by the original author and add chroot to the project directories.

ie:

/home/project1/
/home/project2/

Now each site's index.php is actually:

/web/index.php   (project1)
/web/index.php   (project2)


Somehow this also causes a collision in the cache and causes PHP to serve the wrong index.php from cache if you hit project1 first followed by project2 next.
 [2014-09-10 06:16 UTC] spam at rw23 dot de
its a common problem and also a deal-breaker when using chrooted enviroments like the php-fpm setup, you can find many complains on the net:
https://www.google.com/search?q=php-fpm+chroot+opcache.so

by using a config file from a wrong neighbor project, this bug can even break things.
this is not happening with APC or xcache, so these work around the problem somehow.
 [2014-09-10 06:19 UTC] spam at rw23 dot de
php version is 5.5.16 for me
 [2014-09-10 06:46 UTC] spam at rw23 dot de
This is also a big security issue for two reasons:
1. it allows to read files from other chroots (containing secrets)
if you know another chroot vhost (project1) is running a wordpress installation, you can create a file with a path existing on project1 like /web/wp-config.php in project2, include it from project2 and then echo DB_PASSWORD, DB_HOST and so on. you can read the secrets from project1.

2. i have not tried it, but i think it allows to override files on other chroots and inject arbitrary code.
you can create a /web/index.php containing a php backdoor. if the opcache for that file gets cleared (server restart, garbage collection) and your file is the first loaded into cache again, you have your code executed in other chroots.

a user running chroots without overlapping files will not notice this problem, bringing this vulnerability into production enviroments.
 [2014-09-24 22:30 UTC] public+php dot net at bastelstu dot be
It would be great to be able to specify a prefix for the opcache key. This would easily allow to separate the caches for different pools.
 [2015-01-01 22:11 UTC] Danack at basereality dot com
-Status: Open +Status: Closed
 [2015-01-01 22:11 UTC] Danack at basereality dot com
It turns out this is not a bug, it is the behaviour that is expected when opcache.use_cwd is set to zero.

With it set to zero OPCache does not include the current path in the name used for the cached script, and so OPcache cannot tell two scripts with the same name in different directories apart.

The setting opcache.use_cwd should always be enabled unless PHP is going to be running a single application with known unique file names.
 [2015-01-02 02:43 UTC] public+php dot net at bastelstu dot be
It also happens when using a chroot and several identical applications in different pools. As the applications are identical the paths obviously are as well. This really should be fixed, e.g. by prefixing the cache name with the pool name.
 [2015-01-05 07:40 UTC] spam at rw23 dot de
yes, chroots are really THE problem and it renders the opcache completely unusable in multi-domain hosting enviroments. 
More importantly, this can cause security, privacy and !data-integrity! issues if users do not recognize quickly that it is broken.
I actually had the issue that webshops hosted at my server were displaying products from completely different domains, because the config files had the same path and the same config is executed for all domains. I had a hard time explaining that to my customers.

Finally i did fall back to xcache, it works with chroot so i think it should also work with the official opcache too. This is a serious issue, please reopen this bug.
 [2015-01-05 14:39 UTC] Danack at basereality dot com
@public+php dot net at bastelstu dot be +  @spam at rw23 dot de

Those are different cases from the issue that I originally reported. Please open a separate feature request.
 [2015-03-05 12:16 UTC] tomek at lutel dot pl
@Danack at basereality dot com

Why do you say its different issue? Chrooting is impossible with webcache due to faulty opcache file handling. Could you reopen this bug please, and not call it a feature please? :)
 [2015-06-06 06:03 UTC] kelemen dot samuel at gmail dot com
op cache is really unusable with identical applications (same or similar directory structure) on same hosting. 

We need more specify cache for one file, eg. absolute filepath? Or if this is how opcache was designed then disable this feature by default.
 [2015-09-03 10:39 UTC] admin at 3dr dot org
We can confirm that. Because of this bug opcache is unusable in chroot.
 [2016-08-08 11:05 UTC] rgpublic at gmx dot net
Related to/Duplicate?: https://bugs.php.net/bug.php?id=69090
 [2016-08-08 11:50 UTC] spam at rw23 dot de
yes, its duplicate.

this is a big issue with fatal consequences, and it is still just ignored :(
 [2016-10-28 11:05 UTC] sander dot dbeer at gmail dot com
Problem also exists in PHP 7. Opcache is useless in a chrooted production environment.

It's appalling how this problem is ignored ...
 [2016-11-04 21:43 UTC] php-dev at coydogsoftware dot net
I've posted a proposed patch for the cross-user cache access vulnerability to https://bugs.php.net/bug.php?id=69090 . It doesn't solve the problem in all chroot cases, but it will solve it if the chroot environments run PHP scripts as different system users. My fix might not be perfect, but after 2 years of inaction on this bug I think it's better than nothing.
 [2017-06-26 07:01 UTC] spam at rw23 dot de
Confirmed to still be a problem in PHP7. Cant understand why nobody cares about it, this is a real bug that causes data corrution, confusion and security problems!

My Workaround (PHP5/PHP7) is this:
i have htdocs directory inside my chroot.
rename this to htdocs.someuniqueid and created a symlink from htdocs to htdocs.someuniqueid. restart php-fpm.
the opcache will use the realpath (the path after resolution of all symlinks) and therefore the path with the unique id. by using the symlink, other configurations can stay unchanged.

My workaround in php5 was to uninstall opcache and use xcache, but as xcache is not available anymore with php7.
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Wed Jul 26 00:01:37 2017 UTC