Bug #18623
closedclass.t3lib_exec.php prevents extension to work under PHP hardening
Added by Xavier Perseguers over 16 years ago. Updated about 6 years ago.
0%
Description
When trying to use dam_index with index services using external tools such as pdftotext or exiftags, the BE reported that these tools were not available although some of them were used with indexed_search without any problem.
The problem relies in t3lib/class.t3lib_exec.php when checking if an external tool is executable or not. My server configuration is as follows:
PHP: open_basedir /var/www/somedir:/var/www/bin
in /var/www/bin, I have for instance a symbolic link
pdftotext -> /usr/bin/pdftotext
Now a call to is_executable('/usr/bin/pdftotext') always returns false when dealing with a symbolic link inside a directory found in the open_basedir list of directories.
As such, the t3lib_exec class assumes that the external tool pdftotext is not available.
The only solution I found was to list all executables as "openbase_dir":
php_admin_value open_basedir /var/www/somedir:/var/www/bin/pdftotext
(issue imported from #M8130)
Files
t3lib_exec.patch (917 Bytes) t3lib_exec.patch | Administrator Admin, 2008-04-16 20:14 |
Updated by Xavier Perseguers over 16 years ago
The patch takes care of finding out if open_basedir is used and if so, assumes that the administrator knows what he did and returns true for any external tool located as a direct child of a directory listed in open_basedir PHP configuration's property.
Updated by Xavier Perseguers over 16 years ago
According to the description of how open_basedir behaves (http://ch2.php.net/manual/en/features.safe-mode.php#ini.open-basedir), all symbolic links are resolved before methods such as is_link() or is_executable() are called. That is PHP hardening as I did it prevents TYPO3 core's method addService() to work properly although no problem exists.
Updated by Michiel Roos over 16 years ago
I have also found the is_executable to return false in case of links. Since that day I use hard links to all the executables and relink all of them when I update packages on the server.
This works. But still, a code change may be sensible as a lot of users will want to just symlink stuff into the open_basedir.
What about a
if (@is_executable($path.$cmd) || @is_link($path.$cmd)) {
?
Updated by Xavier Perseguers over 16 years ago
I tried the is_link but I figured out that it did not work either. At least with the version of PHP I indcated (which is the stable version on Deban Etch), the is_link function tries to resolve the symbolic link prior to returning True. This leads to a openbase_dir error, just as with is_executable() and as such this method cannot be used either.
Updated by Michiel Roos over 16 years ago
also . . .
open_basedir may be involved. It does not count if you link to files outside of open_basedir
Updated by Xavier Perseguers over 16 years ago
Could you please explain a bit more? I do not understand well your note :-/
What I found is that symbolic links are resolved prior to the execution of the function. That is a link that points outside a directory listed in open_basedir leads to an error although it is just fine to execute a link to an executable outside open_basedir. This is why I think we should allow something in the addService method to either bypass this check or to circumvent it.
Updated by Michiel Roos over 16 years ago
Ok,
Looks like I was not paying attention to the first couple of comments you made on open_basedir.
I made a small test script to test the workings of the functions is_file, is_link and is_executable:
------------------------------------------------------------------------------
function check($cmd, $safeModeExecDir) {
echo '<br/><br/>checking '.$safeModeExecDir.$cmd.'<br/>';
if (is_file($safeModeExecDir.$cmd)) {
echo $cmd.' is a file<br/>';
} else {
echo $cmd.' is not a file<br/>';
}
if (is_executable($safeModeExecDir.$cmd)) {
echo $cmd.' is executable<br/>';
} else {
echo $cmd.' is not executable<br/>';
}
if (is_link($safeModeExecDir.$cmd)) {
echo $cmd.' is a link<br/>';
} else {
echo $cmd.' is not a link<br/>';
}
system($safeModeExecDir.$cmd.' '.$safeModeExecDir.'test.pdf');
}
$safeModeExecDir = '/var/www/php/exec/';
check('ls', $safeModeExecDir);
check('pdfinfo', $safeModeExecDir);
?>
------------------------------------------------------------------------------
My /var/www/php/exec looks as follows:rwxr-xr-x 2 root root 85536 2007-01-30 21:38 ls 1 root root 88773 2008-05-16 09:18 test.pdf
lrwxrwxrwx 1 root root 16 2008-05-16 08:03 pdfinfo -> /usr/bin/pdfinfo
-rw-r--r-
So I have ls as a hard link (copy) and pdfinfo as a symlink
My php.ini looks as follows:
safe_mode = On
safe_mode_gid = On
open_basedir = "/var/www/:.:/var/www/php/exec"
The output of the script is:
------------------------------------------------------------------------------
checking /var/www/php/exec/ls
ls is not a file
ls is not executable
ls is not a link
/var/www/php/exec/test.pdf
checking /var/www/php/exec/pdfinfo
Warning: is_file() [function.is-file]: open_basedir restriction in effect. File(/var/www/php/exec/pdfinfo) is not within the allowed path(s): (/var/www/:.:/var/www/php/exec) in /var/www/dam/fileadmin/test.php on line 5
pdfinfo is not a file
Warning: is_executable() [function.is-executable]: open_basedir restriction in effect. File(/var/www/php/exec/pdfinfo) is not within the allowed path(s): (/var/www/:.:/var/www/php/exec) in /var/www/dam/fileadmin/test.php on line 10
pdfinfo is not executable
Warning: is_link() [function.is-link]: open_basedir restriction in effect. File(/var/www/php/exec/pdfinfo) is not within the allowed path(s): (/var/www/:.:/var/www/php/exec) in /var/www/dam/fileadmin/test.php on line 15
pdfinfo is not a link
Title: Author: XXX: Acrobat PDFMaker 8.1 voor Word Producer: Acrobat Distiller 8.1.0 (Zinloos) CreationDate: Sun Feb 17 22:52:34 2008 ModDate: Mon Feb 18 12:28:38 2008 Tagged: yes Pages: 4 Encrypted: no Page size: 595.22 x 842 pts (A4) File size: 88773 bytes Optimized: yes PDF version: 1.4
------------------------------------------------------------------------------
When I disable open_basedir:
------------------------------------------------------------------------------
checking /var/www/php/exec/ls
ls is not a file
ls is not executable
ls is not a link
/var/www/php/exec/test.pdf
checking /var/www/php/exec/pdfinfo
pdfinfo is not a file
pdfinfo is not executable
pdfinfo is not a link
Title: Author: XXX: Acrobat PDFMaker 8.1 voor Word Producer: Acrobat Distiller 8.1.0 (Zinloos) CreationDate: Sun Feb 17 22:52:34 2008 ModDate: Mon Feb 18 12:28:38 2008 Tagged: yes Pages: 4 Encrypted: no Page size: 595.22 x 842 pts (A4) File size: 88773 bytes Optimized: yes PDF version: 1.4
------------------------------------------------------------------------------
When safe mode and open_Basedir are both off:
------------------------------------------------------------------------------
checking /var/www/php/exec/ls
ls is a file
ls is executable
ls is not a link
/var/www/php/exec/test.pdf
checking /var/www/php/exec/pdfinfo
pdfinfo is a file
pdfinfo is executable
pdfinfo is a link
Title: Author: XXX: Acrobat PDFMaker 8.1 voor Word Producer: Acrobat Distiller 8.1.0 (Zinloos) CreationDate: Sun Feb 17 22:52:34 2008 ModDate: Mon Feb 18 12:28:38 2008 Tagged: yes Pages: 4 Encrypted: no Page size: 595.22 x 842 pts (A4) File size: 88773 bytes Optimized: yes PDF version: 1.4
------------------------------------------------------------------------------
So the conclusion is that PHP basically totally denies all existence of the executables when safe_mode is enabled (with or without open_basedir).
:-)
It still happily executes the programs!
Strange behavior indeed.
Updated by Xavier Perseguers over 16 years ago
Could someone of the core take a look at it? Bug's still here...
Updated by Michiel Roos over 16 years ago
. . . . since it's bugfixing day and all . . .
;-)
Updated by Dmitry Dulepov about 16 years ago
Wouldn't realpath() solve the problem? I.e.
$realpath = realpath($file); $executable = $realpath && is_executable($realpath);
realpath() is supposed to resolve links:
<q>
realpath
(PHP 4, PHP 5)
realpath — Returns canonicalized absolute pathname
Description
string realpath ( string $path )
realpath() expands all symbolic links and resolves references to '/./', '/../' and extra '/' characters in the input path. and return the canonicalized absolute pathname.
</q>
Updated by Xavier Perseguers about 16 years ago
Yes but as explained in comment 0022032 by Michiel, is_executable still always return FALSE when given a symbolic link as parameter that points out of the open_basedir list.
Updated by Christian Kuhn over 15 years ago
Set to resolved, "not fixable"
Quote from Xavier:
I agreed to reject this bug (with proper comment) as we'll not agree
on a solution for this weird situation.
Dig into core list discussion for better explanation.
Please reopen if I messed something up.