Page MenuHomePhabricator

math.php is not compatible with php safe_mode, fix enclosed
Closed, DeclinedPublic

Description

Author: xGJZ4PX7OxwDENAFc

Description:
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 );


Version: unspecified
Severity: normal

Details

Reference
bz3891

Event Timeline

bzimport raised the priority of this task from to Lowest.Nov 21 2014, 8:53 PM
bzimport added a project: Math.
bzimport set Reference to bz3891.
bzimport added a subscriber: Unknown Object (MLST).

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.

xGJZ4PX7OxwDENAFc wrote:

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?

robchur wrote:

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.

xGJZ4PX7OxwDENAFc wrote:

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.)

xGJZ4PX7OxwDENAFc wrote:

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.

xGJZ4PX7OxwDENAFc wrote:

./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.

zigger wrote:

(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

  1. 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

xGJZ4PX7OxwDENAFc wrote:

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?

xGJZ4PX7OxwDENAFc wrote:

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?

xGJZ4PX7OxwDENAFc wrote:

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().

Created attachment 1053
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.

Attached:

xGJZ4PX7OxwDENAFc wrote:

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.

xGJZ4PX7OxwDENAFc wrote:

and it only took 6 years to come to that conclusion.