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

 ID:                 54110
 User updated by:    carsten_sttgt at gmx dot de
 Reported by:        carsten_sttgt at gmx dot de
 Summary:            tsrm_realpath_r and junction point with denied read
                     access
 Status:             Assigned
 Type:               Bug
 Package:            Filesystem function related
 Operating System:   Windows
 PHP Version:        Irrelevant
 Assigned To:        pajoye
 Block user comment: N
 Private report:     N

 New Comment:

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.


Previous Comments:
------------------------------------------------------------------------
[2011-02-28 17:38:52] paj...@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] paj...@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.

------------------------------------------------------------------------
[2011-02-27 19:50:29] paj...@php.net

It is not only about windows (sometimes very confusing) ways to
configure ACL but portability in the way permissions or what we allow or
not work.



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.

------------------------------------------------------------------------
[2011-02-27 16:58:33] carsten_sttgt at gmx dot de

> Junction does work very well.



You have tested this?

| mklink test1 nonexistent

| mklink /j test2 nonexistent

| php -r "var_dump(realpath('test1'));"

| php -r "var_dump(realpath('test2'));"

What did you expect? (You can also test it with the sample exe below)





> We had similar cases where someone wanted to access stat 

> info from an unreadable file.



It's a difference, if generic read access is denied, or data read
access. This still allows me to other things with an object, e.g reading
attributes or permissions...





> I'm somehow not convinced that we should allow that now.



PHP can't allow me, what is not allowed/possible from the ACL. It's just
working wrong in this piece of code. Because:

- I have full rights on e.g. test1\test.php

- But PHP don't let me do anything with this file

That's just wrong.



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's something like:

| #include <windows.h>

| #include <tchar.h>

| #include <stdio.h>

| 

| void _tmain(int argc, TCHAR *argv[]) {

|     HANDLE hFile;

|     TCHAR  buffer[MAX_PATH]=TEXT(""); 

| 

|     if (GetFullPathName(argv[1], MAX_PATH, buffer, NULL)) {

|         hFile = CreateFile(

|             buffer, 0, 0, NULL, OPEN_EXISTING,

|             FILE_FLAG_BACKUP_SEMANTICS, NULL

|         );

|         if (hFile != INVALID_HANDLE_VALUE) { 

|             _tprintf(TEXT("The full path name is:  %s\n"), buffer);

|             CloseHandle(hFile);

|             exit(EXIT_SUCCESS);

|         }

|     }

|     _tprintf(TEXT("GetFullPathName failed (%d)\n"), GetLastError());

|     exit(EXIT_FAILURE);

| }

(ok, this simple example does not resolve the final pathname from a
symlink)



Such a function must not have GENERIC_READ as DesiredAccess, because it
doesn't want read any data from any object. Especially it doesn't know
what I want do with this file(name) at another place. The final access
control and opening the handle for the real work is done at another
place.



And of course. If generic access is denied from the ACL, CreateFile with
"0" also fail. (you can't do things which are not allowed...)

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


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

    http://bugs.php.net/bug.php?id=54110


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

Reply via email to