Do not allow access to setfenv() and getfenv() by default

Optionally remove setfenv and getfenv from the global environment in
which user code runs. This will improve the forwards-compatibility of
user code with Lua 5.2.

Porting to Lua 5.2 would still be a daunting project, of questionable
value, but at least only the internal code would need updating, and not
thousands of on-wiki modules. Compared to the environment changes, the
rest of the Lua 5.2 changes are relatively easy to simulate for
backwards compatibility.

Removed module() from the package module, since it depends on setfenv().
The native version of it is deprecated in Lua 5.2 for that reason.

Change-Id: I978903ca98943ac941833da13fe5027949f6b429
This commit is contained in:
Tim Starling 2012-05-23 16:51:59 +10:00
parent 886c6ae06d
commit 441943bd9b
6 changed files with 27 additions and 28 deletions

View file

@ -92,6 +92,13 @@ $wgScribuntoEngineConf = array(
'class' => 'Scribunto_LuaSandboxEngine', 'class' => 'Scribunto_LuaSandboxEngine',
'memoryLimit' => 50 * 1024 * 1024, 'memoryLimit' => 50 * 1024 * 1024,
'cpuLimit' => 7, 'cpuLimit' => 7,
// Set this to true to allow setfenv() and getfenv() in user code.
// Note that these functions have been removed in Lua 5.2. Scribunto
// does not yet support Lua 5.2, but we expect support will be
// implemented in the future, and there is no guarantee that a
// simulation of setfenv() and getfenv() will be provided.
'allowEnvFuncs' => false,
), ),
'luastandalone' => array( 'luastandalone' => array(
'class' => 'Scribunto_LuaStandaloneEngine', 'class' => 'Scribunto_LuaStandaloneEngine',
@ -105,6 +112,7 @@ $wgScribuntoEngineConf = array(
'luaPath' => null, 'luaPath' => null,
'memoryLimit' => 50 * 1024 * 1024, 'memoryLimit' => 50 * 1024 * 1024,
'cpuLimit' => 7, 'cpuLimit' => 7,
'allowEnvFuncs' => false,
), ),
); );

View file

@ -52,7 +52,8 @@ abstract class Scribunto_LuaEngine extends ScribuntoEngineBase {
'preprocess' => array( $this, 'preprocess' ), 'preprocess' => array( $this, 'preprocess' ),
) ); ) );
$this->interpreter->callFunction( $this->mw['setup'] ); $this->interpreter->callFunction( $this->mw['setup'],
array( 'allowEnvFuncs' => $this->options['allowEnvFuncs'] ) );
} }
/** /**

View file

@ -4,6 +4,7 @@ local packageCache
local packageModuleFunc local packageModuleFunc
local php local php
local setupDone local setupDone
local allowEnvFuncs = false
--- Put an isolation-friendly package module into the specified environment --- Put an isolation-friendly package module into the specified environment
-- table. The package module will have an empty cache, because caching of -- table. The package module will have an empty cache, because caching of
@ -39,7 +40,7 @@ end
--- Set up the base environment. The PHP host calls this function after any --- Set up the base environment. The PHP host calls this function after any
-- necessary host-side initialisation has been done. -- necessary host-side initialisation has been done.
function mw.setup() function mw.setup( options )
if setupDone then if setupDone then
return return
end end
@ -56,6 +57,10 @@ function mw.setup()
end end
end end
if options.allowEnvFuncs then
allowEnvFuncs = true
end
-- Make mw_php private -- Make mw_php private
-- --
-- mw_php.loadPackage() returns function values with their environment -- mw_php.loadPackage() returns function values with their environment
@ -108,7 +113,14 @@ end
function mw.executeModule( chunk ) function mw.executeModule( chunk )
local env = mw.clone( _G ) local env = mw.clone( _G )
makePackageModule( env ) makePackageModule( env )
env.setfenv, env.getfenv = mw.makeProtectedEnvFuncs( {[_G] = true}, {} )
if allowEnvFuncs then
env.setfenv, env.getfenv = mw.makeProtectedEnvFuncs( {[_G] = true}, {} )
else
env.setfenv = nil
env.getfenv = nil
end
setfenv( chunk, env ) setfenv( chunk, env )
return chunk() return chunk()
end end

View file

@ -24,7 +24,7 @@
--]] --]]
local assert, error, getfenv, ipairs, pairs, setfenv, setmetatable, type = assert, error, getfenv, ipairs, pairs, setfenv, setmetatable, type local assert, error, ipairs, pairs, setmetatable, type = assert, error, ipairs, pairs, setmetatable, type
local find, format, gfind, gsub, sub = string.find, string.format, string.gfind, string.gsub, string.sub local find, format, gfind, gsub, sub = string.find, string.format, string.gfind, string.gsub, string.sub
-- --
@ -135,27 +135,3 @@ function _PACKAGE.seeall (module)
end end
meta.__index = _G meta.__index = _G
end end
--
-- module function
--
function _G.module (modname, ...)
local ns = _LOADED[modname]
if type(ns) ~= "table" then
ns = findtable (_G, modname)
if not ns then
error (string.format ("name conflict for module '%s'", modname))
end
_LOADED[modname] = ns
end
if not ns._NAME then
ns._NAME = modname
ns._M = ns
ns._PACKAGE = gsub (modname, "[^.]*$", "")
end
setfenv (2, ns)
for i, f in ipairs (...) do
f (ns)
end
end

View file

@ -7,6 +7,7 @@ class Scribunto_LuaSandboxEngineTest extends Scribunto_LuaEngineTest {
var $stdOpts = array( var $stdOpts = array(
'memoryLimit' => 50000000, 'memoryLimit' => 50000000,
'cpuLimit' => 30, 'cpuLimit' => 30,
'allowEnvFuncs' => true,
); );
function newEngine( $opts = array() ) { function newEngine( $opts = array() ) {

View file

@ -9,6 +9,7 @@ class Scribunto_LuaStandaloneEngineTest extends Scribunto_LuaEngineTest {
'luaPath' => null, 'luaPath' => null,
'memoryLimit' => 50000000, 'memoryLimit' => 50000000,
'cpuLimit' => 30, 'cpuLimit' => 30,
'allowEnvFuncs' => true,
); );
function newEngine( $opts = array() ) { function newEngine( $opts = array() ) {