PHP 4.0 Bug #3640: memory overwrite in expand_filepath when using include("../somefile.inc")
| From: | gwh at acm dot org | Date: | Sun, 27 Feb 2000 04:09:27 +0000 |
| Subject: | PHP 4.0 Bug #3640: memory overwrite in expand_filepath when using include("../somefile.inc") | ||
| Groups: | php.dev | ||
| Request: | Send a blank email to php-dev+get-16067@lists.php.net to get a copy of this message | ||
From: gwh@acm.org
Operating system: Windows NT 4.0 Server SP 5
PHP version: 4.0 Beta 4 Patch Level 1
PHP Bug Type: Reproduceable crash
Bug description: memory overwrite in expand_filepath when using
include("../somefile.inc")
modules utilized in this test: (commented out all extensions, recompiled debug non thread safe under
VC++5)
php.exe
phpnts.dll
Friends,
It took me a while to figure this out, since I have run the same code on all versions from php3
through the php4 betas and onto php4pl1, without this type of failure. Here is the problem. I may be
the only one that uses an include statement of a file in a parent directory, but it's failing
now. . I've distilled it down to two simple scripts.
lets say your sites sit under the path: d:\websites\website1
place the script "empty.inc" in the directory d:\websites, containing
<?php
print("empty");
?>
place another script "testempty.php" in the directory d:\websites\websites1, containing
<?php
include("../empty.inc");
print("testempty");
?>
my document root is d:\websites\websites1 and when I reference http:\\website1\testempty.php I get a debug assertion (
rebuilt the modules in debug mode, non threadsafe, compiled in VC5.0 ) in dbgheap.c, line 1017, in
the function free_dbg_lk. Here is the backtrace:
dbgheap.c, 1017: _free_dbg_lk(void *,int)
dbgheap.c, 970: _free_dbg(void *,int)
dbgheap.c, 926: free(void *)
fopen-wrappers.c, 989: expand_filepath(char *)
fopen-wrappers.c, 336: php_open_with_path(char *,char *,char *,char *)
...
The problem occurs in expand_filepath() .... It is passed the pathname of "../empty.inc".
The parent directory file reference causes this code to execute in line 976:
if(filepath[1] == '.') {
/*erase the last directory name from the path */
while(*cwd_end != '/') {
*cwd_end--=0;
}
filepath++;
}
if(cwd_end > cwd && (*cwd_end == '/') {
*cwd_end-- = 0;
}
The problem happens because on windows getcwd() returns "d:\websites\website1". Notice the
back slashes. I don't know why this hasn't failed before. The loop
while(*cwd_end!='/') *cwd_end--=0 happily zeros the string going back, back,
ba,ba,ba,ba,ba,ba baaaak (chris berman, ESPN) until it finds a forward slash.
When it gets down to the statement "free(cwd)" in line 989, all of the malloc information
is destroyed and it asserts, and would cause an exception if it goes any further.
I modified the code to add another check for the alternate case :
if(filepath[1] == '.') {
/*erase the last directory name from the path */
while(*cwd_end != '/' && *cwd_end != '\\') {
*cwd_end--=0;
}
filepath++;
}
if(cwd_end > cwd && (*cwd_end == '/' || *cwd_end=='\\') {
*cwd_end-- = 0;
}
This compiled and worked wonderfully. I scanned the rest of the code for getcwd() andI didn't
see another direct exposures due to the slashes on windows.
Regards,
Garfield