From: Tim Starling Date: Sun, 13 Jan 2013 22:48:03 +0000 (+1100) Subject: Implement wall clock time limits for shell commands X-Git-Tag: 1.31.0-rc.0~21046 X-Git-Url: http://git.cyclocoop.org/%24self?a=commitdiff_plain;h=c8e3fa04dbd8f0f185cfab138379a73d2a1227b5;p=lhc%2Fweb%2Fwiklou.git Implement wall clock time limits for shell commands * Use the "timeout" command to implement wall clock time limits. * Write a message to stderr when the time limit is exceeded, for consistency with ulimit * Configure with $wgMaxShellWallClockTime * If "time" is specified in $limits, use that as the wall clock limit in preference to the global variable, to support legacy callers which usually want to disable the limits. * Remove the requirement for ulimit5.sh to be executable since this is not necessary when you specify the interpreter. Should avoid subtle problems when the executable bit is accidentally stripped. * Move the interpretation of 0/-1/false limits to the shell script, so that e.g. wall clock time can be limited even if memory is unlimited. Change-Id: Id9f2fea7c3b027565bdc33b88a1a7d4cdfe43a6c --- diff --git a/RELEASE-NOTES-1.21 b/RELEASE-NOTES-1.21 index ee49e09934..b8f3ba6325 100644 --- a/RELEASE-NOTES-1.21 +++ b/RELEASE-NOTES-1.21 @@ -84,6 +84,8 @@ production. in MW 1.20 (saving preferences using Special:Preferences cleared any additional fields) and which has been disabled in 1.20.1 as a part of a security fix (bug 42202). +* Added the ability to limit the wall clock time used by shell processes, + as well as the CPU time. Configurable with $wgMaxShellWallClockTime. === Bug fixes in 1.21 === * (bug 40353) SpecialDoubleRedirect should support interwiki redirects. diff --git a/bin/ulimit4.sh b/bin/ulimit4.sh deleted file mode 100755 index 2a840d2f7f..0000000000 --- a/bin/ulimit4.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -ulimit -t $1 -v $2 -f $3 -eval "$4" diff --git a/bin/ulimit5.sh b/bin/ulimit5.sh new file mode 100644 index 0000000000..3f24172105 --- /dev/null +++ b/bin/ulimit5.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +if [ "$1" -gt 0 ]; then + ulimit -t "$1" +fi +if [ "$2" -gt 0 ]; then + ulimit -v "$2" +fi +if [ "$3" -gt 0 ]; then + ulimit -f "$3" +fi +if [ "$4" -gt 0 ]; then + timeout $4 /bin/bash -c "$5" + STATUS="$?" + if [ "$STATUS" == 124 ]; then + echo "ulimit5.sh: timed out." 1>&2 + fi + exit "$STATUS" +else + eval "$5" +fi diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index d254ef6077..f41c7aa0d7 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -6108,10 +6108,16 @@ $wgMaxShellMemory = 102400; $wgMaxShellFileSize = 102400; /** - * Maximum CPU time in seconds for shell processes under linux + * Maximum CPU time in seconds for shell processes under Linux */ $wgMaxShellTime = 180; +/** + * Maximum wall clock time (i.e. real time, of the kind the clock on the wall + * would measure) in seconds for shell processes under Linux + */ +$wgMaxShellWallClockTime = 180; + /** * Executable path of the PHP cli binary (php/php5). Should be set up on install. */ diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index 28cc0012cc..0b1bd19acc 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -2767,12 +2767,13 @@ function wfEscapeShellArg( ) { * (non-zero is usually failure) * @param $environ Array optional environment variables which should be * added to the executed command environment. - * @param $limits Array optional array with limits(filesize, memory, time) + * @param $limits Array optional array with limits(filesize, memory, time, walltime) * this overwrites the global wgShellMax* limits. * @return string collected stdout as a string (trailing newlines stripped) */ function wfShellExec( $cmd, &$retval = null, $environ = array(), $limits = array() ) { - global $IP, $wgMaxShellMemory, $wgMaxShellFileSize, $wgMaxShellTime; + global $IP, $wgMaxShellMemory, $wgMaxShellFileSize, $wgMaxShellTime, + $wgMaxShellWallClockTime; static $disabled; if ( is_null( $disabled ) ) { @@ -2820,14 +2821,19 @@ function wfShellExec( $cmd, &$retval = null, $environ = array(), $limits = array if ( php_uname( 's' ) == 'Linux' ) { $time = intval ( isset($limits['time']) ? $limits['time'] : $wgMaxShellTime ); + if ( isset( $limits['walltime'] ) ) { + $wallTime = intval( $limits['walltime'] ); + } elseif ( isset( $limits['time'] ) ) { + $wallTime = $time; + } else { + $wallTime = intval( $wgMaxShellWallClockTime ); + } $mem = intval ( isset($limits['memory']) ? $limits['memory'] : $wgMaxShellMemory ); $filesize = intval ( isset($limits['filesize']) ? $limits['filesize'] : $wgMaxShellFileSize ); - if ( $time > 0 && $mem > 0 ) { - $script = "$IP/bin/ulimit4.sh"; - if ( is_executable( $script ) ) { - $cmd = '/bin/bash ' . escapeshellarg( $script ) . " $time $mem $filesize " . escapeshellarg( $cmd ); - } + if ( $time > 0 || $mem > 0 || $filesize > 0 || $wallTime > 0 ) { + $cmd = '/bin/bash ' . escapeshellarg( "$IP/bin/ulimit5.sh" ) . + " $time $mem $filesize $wallTime " . escapeshellarg( $cmd ); } } wfDebug( "wfShellExec: $cmd\n" );