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.
This commit is contained in:
Enrique García Cota 2021-01-05 00:43:04 +01:00 committed by Enrique García Cota
parent 50bfa4abca
commit 485a14697c
3 changed files with 34 additions and 21 deletions

View File

@ -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.

View File

@ -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))

View File

@ -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()