php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Doc Bug #40535 is_readable and file_exists give false negatives when euid != uid
Submitted: 2007-02-18 17:35 UTC Modified: 2007-03-23 16:09 UTC
From: php dot user at jeremy dot smallinfinity dot net Assigned:
Status: Closed Package: Documentation problem
PHP Version: 5.2.1 OS: MacOS and RedHat Linux
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If this is not your bug, you can add a comment by following this link.
If this is your bug, but you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: php dot user at jeremy dot smallinfinity dot net
New email:
PHP Version: OS:

 

 [2007-02-18 17:35 UTC] php dot user at jeremy dot smallinfinity dot net
Description:
------------
is_readable() and file_exists(), when called from a PHP 4.3.2 (Linux), 4.4.0 (Mac OS) and 5.2.1 (Mac OS) script that is executed with posix_euid() != posix_uid() does not recognize files that are owned and readable only by the effective uid.  Instead is_readable() and file_exists() return "false" even though functions like fileperms, fopen and readfile work as expected.

Reproduce code:
---------------
#!/usr/bin/php
<?php
echo "My effective UID is ".posix_geteuid()." but my UID is really ".posix_getuid()."\n";

chdir($curdir = dirname(__FILE__)) or die("Unable to enter the private directory");
echo "The current directory is owned by ".fileowner($curdir)." and has permissions ".sprintf('%o', fileperms($curdir))."\n";

touch("test.dat");
chmod("test.dat", 0600); // readable only by the effective user

echo "is_readable should give TRUE, and gives ".(is_readable("test.dat") ? "TRUE" : "FALSE")."\n";

echo "file_exists should give TRUE, and gives ".(file_exists("test.dat") ? "TRUE" : "FALSE")."\n";

echo "The file has permissions ".sprintf('%o', fileperms("test.dat")).", is owned by ".fileowner("test.dat")." and is in the ".filegroup("test.dat")." group.\n";

unlink("test.dat"); // no error because the file really does exist!

?>

Expected result:
----------------
My effective UID is 501 but my UID is really [uid]
The current directory is owned by 501 and has permissions 40700
is_readable should give TRUE, and gives TRUE
file_exists should give TRUE, and gives TRUE
The file has permissions 100600, is owned by 501 and is in the 501 group.

Actual result:
--------------
When run as its owner, gives the expected result, with [uid]=501.

When run from a different account using the executable obtained from
#include <unistd.h>

int main(int argc, char **argv) {
  execl("/path/to/reproduce_code.php", "/path/to/reproduce_code.php", NULL);

}
which is then chmod 04711 or 06711, gives

My effective UID is 501 but my UID is really 503
The current directory is owned by 501 and has permissions 40700
is_readable should give TRUE, and gives FALSE
file_exists should give TRUE, and gives FALSE
The file has permissions 100600, is owned by 501 and is in the 501 group.

These tests are done on Mac OS X 10.4.8 with both PHP 4.4.4 and 5.2.1, but I first noticed this behaviour with PHP 4.3.2 under Red Hat Linux for which I do not have root privileges.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2007-02-27 13:40 UTC] tony2001@php.net
PHP uses access() function.

man access:
The check is done with the process's real UID and GID, rather than with the effective IDs as is done when actually attempting an operation.  This is to allow  set-UID programs to easily determine the invoking user's authority.

 [2007-02-27 15:00 UTC] php dot user at jeremy dot smallinfinity dot net
Thanks.

I understand that PHP uses access() and that access() behaves as per its man page.  I also understand that this is one way of fixing e.g. Bug#30931.  But I don't understand why that implies that is_readable() and file_exists() are *supposed to* behave according to the access() man page.  Aren't is_readable() and file_exists() supposed to behave as described in the PHP manual?  Nowhere therein does it specify that the check is done using the real UID/GID instead of the effective one.  And I'm afraid I don't understand why checking the real UID/GID is the desired behaviour.

Thanks,
Jeremy
 [2007-02-27 15:05 UTC] tony2001@php.net
> Nowhere therein does it specify that the check is done
> using the real UID/GID instead of the effective one.

Reclassified a docu problem.
Feel free to help the documentation team in documenting this behavior.
 [2007-03-23 16:09 UTC] vrana@php.net
This bug has been fixed in the documentation's XML sources. Since the
online and downloadable versions of the documentation need some time
to get updated, we would like to ask you to be a bit patient.

Thank you for the report, and for helping us make our documentation better.

"The check is done using the real UID/GID instead of the effective one."
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Mar 28 17:01:29 2024 UTC