Bug #54110 [Asn->Opn]: tsrm_realpath_r and junction point with denied read access

From: Date: Tue, 24 Oct 2017 07:33:48 +0000
Subject: Bug #54110 [Asn->Opn]: tsrm_realpath_r and junction point with denied read access
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-212106@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=54110&edit=1

 ID:                 54110
 Updated by:         kalle@php.net
 Reported by:        carsten_sttgt at gmx dot de
 Summary:            tsrm_realpath_r and junction point with denied read
                     access
-Status:             Assigned
+Status:             Open
 Type:               Bug
 Package:            Filesystem function related
 Operating System:   Windows
 PHP Version:        Irrelevant
-Assigned To:        pajoye
+Assigned To:        
 Block user comment: N
 Private report:     N



Previous Comments:
------------------------------------------------------------------------
[2012-03-02 14:49:53] ab@php.net

After taking a look at the stuff I've realized that there is a FindFirstFile 
invocation in TSRM/tsrm_virtual_cwd.c around line 852. There is a check for 
INVALID_HANDLE_VALUE after which "return -1" happens. If I do the following 
after FindFirstFile fails 

DWORD dw = GetLastError();

if (ERROR_ACCESS_DENIED == dw) {
	/* inside junction ? */
}

I see that it happens for exactly the case trying to read "test\test.txt" from 
the initial example. A 'not found' status is given for nonexistent files

A solution I'm thinking about is to traverse all the parents until the first 
junction, after that the junction target can be resolved and the complete real 
path could be built. This could be done with the check above for this specific 
case. Not sure if there would be impacts on dependant functionality

------------------------------------------------------------------------
[2011-03-02 19:44:17] carsten_sttgt at gmx dot de

OK and sorry. So let me add this to this topic...
Assuming a default Windows/IIS installation:
| <?php
| $temp = tmpfile();
| $filedata = stream_get_meta_data($temp);
| var_dump(realpath($filedata['uri']));
| ?>

The result:
| boolean false

But it's a little bit different to the problem above. fopen() etc. is working. Only realpath()
fails. And the patch above doesn't fix this issue.

------------------------------------------------------------------------
[2011-02-28 17:38:52] pajoye@php.net

The main problem we have is about the incldue/require _once function, 
permissions issues (no meta read if no permission (as in no read)), etc.

I'm working on droping almost all useless path resolution for (f)open and 
related functions. They should do nothing but create the file or the file 
handle, instead of checking each part of the request path.

But that's a very (very) sensible part of php and I'm reluctant to make changes 
too quickly in this area for an edge case. At least not without clear test 
cases.

We have a bunch of tests covering this code but it takes some time to run them, 
fix, re test, etc. So don't hold your breath, it won't happen before 5.3.6 is 
released :)

Thanks for your feedback!

------------------------------------------------------------------------
[2011-02-28 17:32:31] carsten_sttgt at gmx dot de

> I'm also not sure that what you proposed does not break more
> that what it solves. I will double check that later in March.

That's ok. BTW, this will also fix Bug #50659 (but read below). In the meantime: Maybe you want
add "FILE_SHARE_READ as 3rd Parameters for CreateFile (to prevent a race condition).


> It does not only do that and it is used for more than that.
Oh, look like complicated code for doing some task without description what the function is doing
;-)

Well, it's resolving a relative path to an absolute one, testing if the target 
exists. And it's resolving symlinks along the path. What else?
(really a pity that GetFinalPathNameByHandle only exists as of Vista.)

Especially the last (and because it's called in most functions, although the functions can use
relative paths directly.) raises some problems. I guess that's for this openbasedir check?

Well, according to #50659 I have a real live issue for a similar reason (and why I'm using ASP
for one project and not PHP):

Given a WEBSERVER which is using a share "Files" on FILESERVER (//FILESERVER/Files).

"Files" is the directory "D:\Files". Some Videos are located at
"E:\Videos" and there is a junction from "D:\Files\Videos" to
"E:\Videos".

Ok, now on WEBSERVER I'm using PHP to access "//FILESERVER/Files/Videos/". What is
PHP doing?
It's resolving the last junction to "E:\Videos" and thus it's searching rhis
directory on WEBSERVER. Still curious this doesn't happen with every function:
"passtru('//FILESERVER/Files/Videos/foo.mpg');" is working.
"$f=fopen('//FILESERVER/Files/Videos/foo.mpg', 'rb'); fpassthru($f);"
not.

Well, I guess resolving symlinks should only be done on local drives (or let CreateFile in fopen
doing this job itself).

------------------------------------------------------------------------
[2011-02-27 19:51:42] pajoye@php.net

"Maybe we should think about what this function tsrm_realpath_r is doing. It's 
just resolving a relative path to an absolute one. And it's testing if the target 
exists. Nothing else"

It does not only do that and it is used for more than that.

------------------------------------------------------------------------


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=54110


--
Edit this bug report at https://bugs.php.net/bug.php?id=54110&edit=1


Thread (14 messages)

« previous php.bugs (#212106) next »