Skip to content

Instantly share code, notes, and snippets.

@jsimmons
Created July 22, 2010 04:43
Show Gist options
  • Save jsimmons/485579 to your computer and use it in GitHub Desktop.
Save jsimmons/485579 to your computer and use it in GitHub Desktop.
old lua sandboxing code
require "task"
function dothebox( )
local makeReadOnly = function( t )
proxy = {}
mt = {}
mt.__metatable = "None of your business!"
mt.__index = t
mt.__newindex = function( t, k, v )
error( "Can not edit protected tables!" )
end
setmetatable( proxy, mt )
return proxy
end
local protectedTables =
{
"os",
"bit",
"table",
"string",
"math",
"coroutine",
"tostring",
"print",
"pairs",
"next",
"ipairs",
"assert",
"_VERSION",
"_G"
}
local makeProtected = function( t )
proxy = {}
mt = {}
mt.__metatable = "None of your business!"
mt.__index = t
mt.__newindex = function( tab, key, val )
for _, prot in pairs( protectedTables ) do
if key == prot then
error( "Can not edit protected tables!", 2 )
end
end
--tab[key] = val -- update original table
rawset( tab, key, val )
end
setmetatable( proxy, mt )
return proxy
end
local env = {}
env._G = makeProtected( env )
env._VERSION = _VERSION
env.assert = assert
env.ipairs = ipairs
env.next = next
env.pairs = pairs
local toPrint = nil
env.print = function(...)
local s = ""
if arg.n > 1 then
s = arg[1]
arg.n = nil
arg[1] = nil
for k, v in pairs( arg ) do
s = s .. ", " .. tostring( v )
end
else
s = arg[1]
end
if toPrint then
toPrint = toPrint .. ", " .. s
else
toPrint = s
end
end
env.tonumber = tonumber
env.tostring = tostring
env.setmetatable = setmetatable
env.getmetatable = getmetatable
env.type = type
env.coroutine = makeReadOnly( coroutine )
env.math = makeReadOnly( math )
env.string = makeReadOnly( string )
env.table = makeReadOnly( table )
env.bit = makeReadOnly( bit )
env.os = os
env.os.execute = nil
env.os.exit = nil
env.os.getenv = nil
env.os.remove = nil
env.os.rename = nil
env.os.setlocale = nil
env.os.tmpname = nil
env.os = makeReadOnly( env.os )
env = makeProtected( env )
local ret_num_args = function(...) return { n = select( "#", ... ), ... } end
local main_id = arg[1]
while true do
local code, flag, rc = task.receive( 50 )
if rc == 0 then
local func, err = loadstring( "return " .. code );
if not func then
func, err = loadstring( code );
end
if not func then
task.post( main_id, err, 0 );
else
setfenv( func, env )
local args = ret_num_args( pcall( func ) )
if not toPrint then
if args.n > 1 then
local num = args.n
args.n = nil -- should remove the number of args and the true/false entry
args[1] = nil
res = ""
if #args > 1 then
for i = 2, num, 1 do
res = res .. " " .. tostring( args[i] )
end
else
res = tostring( args[3] )
end
task.post( main_id, res, 0 )
else
task.post( main_id, "executed...", 0 )
end
else
res = tostring( toPrint )
toPrint = nil
task.post( main_id, res, 0 )
end
end
end
end
end
main_id = task.id()
tsk = task.create( "=" .. string.dump( dothebox ), { main_id } )
function sandbox( code )
if not task.isrunning( tsk ) then
tsk = task.create( "=" .. string.dump( dothebox ), { main_id } )
if tsk < 0 then return nil end
end
task.post( tsk, code, 0 )
local msg, flag, rc = task.receive( 5000 )
if rc == 0 then
return msg
elseif rc == -2 then
task.cancel( tsk )
return "ERROR: Script execution time of 5s exceeded!"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment