php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #62151 Write permissions needed on all served files
Submitted: 2012-05-25 00:00 UTC Modified: 2012-12-18 04:59 UTC
Votes:4
Avg. Score:4.0 ± 1.0
Reproduced:2 of 3 (66.7%)
Same Version:1 (50.0%)
Same OS:1 (50.0%)
From: danny at tibibi dot com Assigned: pajoye (profile)
Status: Closed Package: APC (PECL)
PHP Version: 5.4.3 OS: Windows7/Windows Server 2008 R2
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: danny at tibibi dot com
New email:
PHP Version: OS:

 

 [2012-05-25 00:00 UTC] danny at tibibi dot com
Description:
------------
I am using php 5.4.1 with APC 3.1.10

You need to give full write permissions to the account running apache on all the files served by apache in order for caching to work. This not good practice.

I have found and fixed the problem in the function apc_restat in apc.c.

hFile = CreateFile(fileinfo->fullpath, GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, NULL);

should be

hFile = CreateFile(fileinfo->fullpath, GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);

Also, the check made to see if the file was opened is not correct.

if (!hFile) {

should be

if (hFile == INVALID_HANDLE_VALUE) {


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-05-25 14:12 UTC] ab@php.net
Hi,

I cannot confirm this on win7/apache2.2/php5.4 . I've just used a small snippet:

<?php

function hello()
{
    echo 'hello';
}
hello();

in file noaccess.php

then removing all the rights for all the users on that file and trying to access it through apache i get:

Warning: Unknown: failed to open stream: Permission denied in Unknown on line 0

Only giving the read permission for the account running apache already makes the file to be executeable by apache+php regardless APC is present or not. Thus, when the PHP code gets executed, APC is in the game by all means.

How exactly you see that caching doesn't work? Please try my example wether you can repro it. All the system policies should be checked as your files might inherit some. The best way would be probably to disable inheritance for that file.
 [2012-05-25 14:50 UTC] danny at tibibi dot com
Giving read access to apache does give PHP+apache access. However, in the code, on the lines I pointed out, the files are trying to be opened with WRITE access, which fails.

I did notice that the actual requested file doesn't go through the same code path, and I forgot to mention this in the bug repro steps.

If you make a call to require_once() in your file noaccess.php, you will see that the required file cannot be opened, and therefore does not get cached.

Please confirm if you get this.

Thanks a lot!
 [2012-05-27 17:08 UTC] ab@php.net
You're right saying that only the code for includes is affected. That's apc.c in apc_restart. I also get an error when I run this snippet on the windows console on a file with readonly permissions:

============ SNIPPET =======================

#include <windows.h>

int
main(int argc, char **argv)
{
        HANDLE hf;

        if (argc < 2) {
                printf("Usage: createfile path\n");
                return 0;
        }

        hf = CreateFile(argv[1],
                           GENERIC_WRITE,
                           FILE_SHARE_WRITE|FILE_SHARE_READ,
                           NULL,
                           OPEN_ALWAYS,
                           FILE_FLAG_BACKUP_SEMANTICS,
                           NULL);

        if (hf == INVALID_HANDLE_VALUE) {
                printf("Could not open %s\n", argv[1]);
                return 3;
        }

        printf("opened %s successfully to write\n", argv[1]);

        return 0;
}

======================= END SNIPPET ==========================

BUT, magically there are still no errors when I'm trying to reproduce this with apache. Very strange :) . I just did as you've said - maid an include in the main file with the read permissions only, but it still works in apache+apc.

The check with "if(!hFile)" should be "hFile == INVALID_HANDLE_VALUE", that's right.

I think there should be more investigation why it doesn't always fail. Could you please provide more detailed error infos?
 [2012-05-28 12:33 UTC] danny at tibibi dot com
I think it will always fail. In your setup, there must be something with the account being used for running apache. On my system, it always fails using apache. If you have apache running as local system account, that account can easily gain access to the file even if it doesn't have write access to begin with. Also, check your permissions on the file. Make sure that no account has any access to the file. If Authenticated Users or System or Administrators is given access to the file, then apache will most probably be able to gain access.

I have apache running as a service under a non-administrator account which only has read access to all the files except for folders that need to be written to.

The error happens on the call to CreateFile and GetLastError() returns 5 (Access Denied).

Is there a reason why GENERIC_WRITE is needed for CreateFile? The fix I have proposed is going to work in all cases, and I don't think not having write access is going to cause any other problems... Am i missing something?

By the way, the version string for APC is still set to 3.1.9
Thanks for looking into this.
 [2012-05-29 20:20 UTC] ab@php.net
Ok, what i did - created a completely new user without admin rights (say "user_nonadmin"), removed all the users on the files except the "user_nonadmin". "user_nonadmin has only read permission on the files. Running apache with "httpd -X" as usual still works (under the same user)!!

Than I've played with ACEs and error conditions, doing

icacls noaccess2.php /remove:d user_nonadmin
icacls noaccess2.php /remove:g user_nonadmin
icacls noaccess2.php /deny user_nonadmin:(F,M,R,RX,W)
icacls noaccess2.php /grant user_nonadmin:(R)

C:\Apache2\htdocs>icacls noaccess2.php
noaccess2.php php-dev-dell\user_nonadmin:(R)

The has only read access to the file, despite write access isn't disallowed explicitly it's by default.

Checking then that snippet with the condition "if(!hFile)" always says it's opened for writing. Using "hFile == INVALID_HANDLE_VALUE" always says it couldn't.

Btw. the same happens with the admin user for me.

Thus I think we have firstly a wrong check condition, it should be "hFile == INVALID_HANDLE_VALUE".

Secondly, as you can read here http://msdn.microsoft.com/en-us/library/windows/desktop/aa364399 :

Note that you cannot use an access-denied ACE to deny only GENERIC_READ or only GENERIC_WRITE access to a file. This is because for file objects, the generic mappings for both GENERIC_READ or GENERIC_WRITE include the SYNCHRONIZE access right. If an ACE denies GENERIC_WRITE access to a trustee, and the trustee requests GENERIC_READ access, the request will fail because the request implicitly includes SYNCHRONIZE access which is implicitly denied by the ACE, and vice versa. Instead of using access-denied ACEs, use access-allowed ACEs to explicitly allow the permitted access rights.

This means for me, exchanging that param with GENERIC_READ would fix the readonly case. Writeonly case would be then broken, but that one is anyway strange to have writeonly files :). Could you repro the stuff i described?

That the apache is still working in any cases is still a puzzle for me. But I think the cli example looks more like correct than apache.
 [2012-05-30 11:40 UTC] danny at tibibi dot com
Hi,

using if (hf == INVALID_HANDLE_VALUE) is definitely needed, otherwise the value returned (INVALID_HANDLE_VALUE) will always pass the comparison if (!hf).

Until I changed this, it seemed like it was opening the file and then failing later.

As for what you say about ACEs, I've always used access-allow ACEs. However, I do not understand what you mean that Write Only files wouldn't work. If you allow write permissions only for the file, that should work when asking for GENERIC_WRITE?

As far as your tests are concerned, you didn't explain what each test gave as a result, but i'm sure that everything coincides with what I get. The only difference is that apache gives me the same results as any other test you did. I do not know why you are having differences running as apache...
 [2012-11-17 09:31 UTC] axc97c at gmail dot com
I have come across the same issue with this code. My files that i am serving are read only, on a windows box 
using a custom php_embed based server. Been trying to work out why apc isnt caching the files correctly and 
tracked it down to this cause.

The files are being opened by 

hFile = CreateFile(fileinfo->fullpath, GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, OPEN_ALWAYS, 
FILE_FLAG_BACKUP_SEMANTICS, NULL);

which will return 0xffffffff (INVALID_HANDLE_VALUE). The next line in the code is if (!hFile) which will never 
trigger the debug error for this. The line should be if (hFile == INVALID_HANDLE_VALUE) for the error to happen 
correctly (see reference to CreateFile at http://msdn.microsoft.com/en-
gb/library/windows/desktop/aa363858(v=vs.85).aspx)

Doing a bit of extra debug the call is failing on a permissions denied error (caused by the file being read 
only), and the GENERIC_WRITE flag asking for write permissions.

If the open line is changed to

hFile = CreateFile(fileinfo->fullpath, GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, OPEN_ALWAYS, 
FILE_FLAG_BACKUP_SEMANTICS, NULL);

then the call operated correctly and everything works fine.

Adam
 [2012-12-18 04:58 UTC] pajoye@php.net
Automatic comment from SVN on behalf of pajoye
Revision: http://svn.php.net/viewvc/?view=revision&amp;revision=328811
Log: - Fixed bug #62151 (Stat files only require read access only, windows)
 [2012-12-18 04:59 UTC] pajoye@php.net
The fix for this bug has been committed.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.

 For Windows:

http://windows.php.net/snapshots/
 
Thank you for the report, and for helping us make PHP better.


 [2012-12-18 04:59 UTC] pajoye@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: pajoye
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 26 12:01:30 2024 UTC