mirror of
https://github.com/kikito/lua-sandbox.git
synced 2024-12-18 03:04:20 +00:00
feat(sandbox) make envs read-only, change the way they are built
This changes envs in three ways: * They are strict read-only. This minimizes the surface attack if someone with malicious intent overrides global stuff on an environment which happens to be reused. * Envs can override the base env * Envs with metatables now use them
This commit is contained in:
parent
7de90f6ccf
commit
e1e0faf150
18
sandbox.lua
18
sandbox.lua
@ -106,13 +106,6 @@ end)
|
||||
|
||||
local string_rep = string.rep
|
||||
|
||||
local function merge(dest, source)
|
||||
for k,v in pairs(source) do
|
||||
dest[k] = dest[k] or v
|
||||
end
|
||||
return dest
|
||||
end
|
||||
|
||||
local function sethook(f, key, quota)
|
||||
if type(debug) ~= 'table' or type(debug.sethook) ~= 'function' then return end
|
||||
debug.sethook(f, key, quota)
|
||||
@ -135,11 +128,16 @@ function sandbox.protect(code, options)
|
||||
quota = options.quota or 500000
|
||||
end
|
||||
|
||||
local env = merge(options.env or {}, BASE_ENV)
|
||||
env._G = env._G or env
|
||||
|
||||
assert(type(code) == 'string', "expected a string")
|
||||
|
||||
local passed_env = options.env or {}
|
||||
local env = {}
|
||||
for k, v in pairs(BASE_ENV) do
|
||||
local pv = passed_env[k]
|
||||
env[k] = pv ~= nil and pv or v
|
||||
end
|
||||
setmetatable(env, { __index = options.env })
|
||||
env._G = env
|
||||
|
||||
local f
|
||||
if bytecode_blocked then
|
||||
|
@ -72,10 +72,10 @@ describe('sandbox.run', function()
|
||||
assert.error(function() sandbox.run("error('this should be raised')") end)
|
||||
end)
|
||||
|
||||
it('DOES persist modification to base functions when they are provided by the base env', function()
|
||||
it('does not persist modification to base functions even when they are provided by the base env', function()
|
||||
local env = {['next'] = 'hello'}
|
||||
sandbox.run('next = "bye"', { env=env })
|
||||
assert.equal(env['next'], 'bye')
|
||||
assert.equal(env['next'], 'hello')
|
||||
end)
|
||||
end)
|
||||
|
||||
@ -111,17 +111,29 @@ describe('sandbox.run', function()
|
||||
it('is available on the sandboxed env as the _G variable', function()
|
||||
local env = {foo = 1}
|
||||
assert.equal(1, sandbox.run("return foo", {env = env}))
|
||||
assert.equal(env, sandbox.run("return _G", {env = env}))
|
||||
assert.equal(1, sandbox.run("return _G.foo", {env = env}))
|
||||
end)
|
||||
|
||||
it('does not hide base env', function()
|
||||
assert.equal('HELLO', sandbox.run("return string.upper(foo)", {env = {foo = 'hello'}}))
|
||||
end)
|
||||
|
||||
it('can modify the env', function()
|
||||
it('cannot modify the env', function()
|
||||
local env = {foo = 1}
|
||||
sandbox.run("foo = 2", {env = env})
|
||||
assert.equal(env.foo, 2)
|
||||
assert.equal(env.foo, 1)
|
||||
end)
|
||||
|
||||
it('uses the env metatable, if it exists', function()
|
||||
local env1 = { foo = 1 }
|
||||
local env2 = { bar = 2 }
|
||||
setmetatable(env2, { __index = env1 })
|
||||
assert.equal(3, sandbox.run("return foo + bar", { env = env2 }))
|
||||
end)
|
||||
|
||||
it('can override the base env', function()
|
||||
local env = { tostring = function(x) return "hello " .. x end }
|
||||
assert.equal("hello peter", sandbox.run("return tostring('peter')", { env = env }))
|
||||
end)
|
||||
end)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user