From 485a14697c625c44b17288d41489f0aa443319b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20Garci=CC=81a=20Cota?= Date: Tue, 5 Jan 2021 00:43:04 +0100 Subject: [PATCH] feat(sandbox) explicitly drop support of quotas on LuaJIT The solution we use in PUC Rio Lua (with debug.sethook) simply does not work in LuaJIT. * We have added a `sandbox.quota_supported` field to signal this feature (or lack of thereof) * We explicitly return an error if `options.quota` is passed on a LuaJIT environment, in order to prevent LuaJIT users from believing that they are protected against infinite loops. --- README.md | 4 +++- sandbox.lua | 11 +++++++++-- spec/sandbox_spec.lua | 40 ++++++++++++++++++++++------------------ 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 264b970..00ee06b 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ sandbox.run('while true do end') -- raise errors after 500000 instructions sandbox.run('while true do end', {quota=10000}) -- raise error after 10000 instructions ``` -Note that if the quota is low enough, sandboxed functions that do lots of calculations might fail: +If the quota is low enough, sandboxed functions that do lots of calculations might fail: ``` lua local f = function() @@ -77,6 +77,8 @@ end sandbox.run(f, {quota=100}) -- raises error before the function ends ``` +Note: This feature is not available in LuaJIT + ### options.env Use the `env` option to inject additional variables to the environment in which the sandboxed function is executed. diff --git a/sandbox.lua b/sandbox.lua index 4ac8ecd..db2cca3 100644 --- a/sandbox.lua +++ b/sandbox.lua @@ -25,9 +25,13 @@ local sandbox = { CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ]] + ]], + } +-- quotas don't work in LuaJIT since debug.sethook works differently there +local quota_supported = type(_G.jit) == "nil" +sandbox.quota_supported = quota_supported -- PUC-Rio Lua 5.1 does not support deactivation of binary code local mode_supported = _ENV or type(_G.jit) == "table" @@ -125,6 +129,9 @@ function sandbox.protect(code, options) options = options or {} local quota = false + if options.quota and not quota_supported then + error("options.quota is not supported on this environment (usually LuaJIT). Please unset options.quota") + end if options.quota ~= false then quota = options.quota or 500000 end @@ -148,7 +155,7 @@ function sandbox.protect(code, options) return function(...) - if quota then + if quota and quota_supported then local timeout = function() cleanup() error('Quota exceeded: ' .. tostring(quota)) diff --git a/spec/sandbox_spec.lua b/spec/sandbox_spec.lua index e0f4295..9155bef 100644 --- a/spec/sandbox_spec.lua +++ b/spec/sandbox_spec.lua @@ -84,27 +84,31 @@ describe('sandbox.run', function() end) - describe('when given infinite loops', function() + if sandbox.quota_supported then + describe('when given infinite loops', function() + it('throws an error with infinite loops', function() + assert.error(function() sandbox.run("while true do end") end) + end) - it('throws an error with infinite loops', function() - assert.error(function() sandbox.run("while true do end") end) + it('restores string.rep even after a while true', function() + assert.error(function() sandbox.run("while true do end") end) + assert.equal('hellohello', string.rep('hello', 2)) + end) + + it('accepts a quota param', function() + assert.has_no.errors(function() sandbox.run("for i=1,100 do end") end) + assert.error(function() sandbox.run("for i=1,100 do end", {quota = 20}) end) + end) + + it('does not use quotes if the quote param is false', function() + assert.has_no.errors(function() sandbox.run("for i=1,1000000 do end", {quota = false}) end) + end) end) - - it('restores string.rep even after a while true', function() - assert.error(function() sandbox.run("while true do end") end) - assert.equal('hellohello', string.rep('hello', 2)) + else + it('throws an error when trying to use the quota option in an unsupported environment (LuaJIT)', function() + assert.error(function() sandbox.run("", {quota = 20}) end) end) - - it('accepts a quota param', function() - assert.has_no.errors(function() sandbox.run("for i=1,100 do end") end) - assert.error(function() sandbox.run("for i=1,100 do end", {quota = 20}) end) - end) - - it('does not use quotes if the quote param is false', function() - assert.has_no.errors(function() sandbox.run("for i=1,1000000 do end", {quota = false}) end) - end) - - end) + end describe('when given an env option', function()