summaryrefslogtreecommitdiff
path: root/lib/supple/sandbox.lua
diff options
context:
space:
mode:
Diffstat (limited to 'lib/supple/sandbox.lua')
-rw-r--r--lib/supple/sandbox.lua128
1 files changed, 128 insertions, 0 deletions
diff --git a/lib/supple/sandbox.lua b/lib/supple/sandbox.lua
new file mode 100644
index 0000000..6b2d3ab
--- /dev/null
+++ b/lib/supple/sandbox.lua
@@ -0,0 +1,128 @@
+-- lib/supple/sandbox.lua
+--
+-- Sandbox (for) Untrusted Procedure Partitioning (in) Lua Engine
+--
+-- Code which runs the core sandbox functionality of supple.
+--
+-- This module runs in the sandbox interpreter which means some of the code
+-- runs with root access. As such, we minimise what can be done before
+-- we drop privileges.
+--
+-- The wrapper used to run us already ensured that LUA_PATH etc are
+-- not set, so we don't have to worry about non-system-installed modules
+-- getting in our way. Once the supple libraries are loaded (which will
+-- include loading luxio etc) we're good to go and can ask the supple.capi
+-- module to lock us down.
+--
+-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org>
+--
+-- For licence terms, see COPYING
+--
+
+local capi = require 'supple.capi'
+local luxio = require 'luxio'
+local sio = require 'luxio.simple'
+
+local load = load
+local setfenv = setfenv
+local type = type
+
+-- Run fn with globs as its globals. Returns a function to run which
+-- returns the return values of fn, and also wrap returns the table
+-- which will be filled with any new globals fn creates.
+--
+-- If fn is a string then it is used as the source of the function, if it
+-- is a function then it is expected to be a closure which when called
+-- repeatedly returns more data loaded (perhaps from a file?). src is
+-- expected to be the name associated with this source code.
+--
+-- In case of error, returns nil, errmsg
+local function _wrap(fn, src, globs)
+ local fn_glob = setmetatable({}, { __index = globs, __metatable=true })
+ local fn_ret, msg
+
+ assert(fn, "No function/source provided?")
+ assert(src, "No source name provided?")
+ globs = globs or {}
+
+ if setfenv then
+ -- Lua 5.1 style load...
+ fn_ret, msg = ((type(fn) == "string") and loadstring or load)(fn, src)
+ if not fn_ret then
+ return nil, msg
+ end
+ setfenv(fn_ret, fn_glob)
+ else
+ -- Lua 5.2 style load...
+ fn_ret, msg = load(fn, src, "t", fn_glob)
+ if not fn_ret then
+ return nil, msg
+ end
+ end
+
+ assert(fn_ret, "Unusual, missing fn_ret now?")
+
+ return fn_ret, fn_glob
+end
+
+local function sandboxed_go()
+ -- Remove ourselves from the globals table so we cannot
+ -- be reentered
+ go = nil;
+
+-- return io.receive()
+ return 0
+end
+
+local function run()
+ -- Run the sandbox
+ local result, errno = capi.lockdown()
+
+ if result ~= "ok"
+-- START_TEST_ONLY
+ and result ~= "oknonroot"
+-- END_TEST_ONLY
+ then
+ -- Failure to sandbox, so abort
+ print(result, luxio.strerror(errno))
+ return errno
+ end
+
+-- START_TEST_ONLY
+ if result ~= "oknonroot" then
+-- END_TEST_ONLY
+ -- Check that we're definitely solidly jailed
+ fh, errno = sio.open("testfile", "rw")
+ if fh then
+ fh:close()
+ luxio.unlink("testfile")
+ return 1
+ end
+-- START_TEST_ONLY
+ end
+-- END_TEST_ONLY
+
+ -- Prepare a severely limited sandbox
+ local sandbox_globals = {}
+
+ for _, k in ipairs({ "table", "string", "pairs", "ipairs", "pcall",
+ "xpcall", "unpack", "tostring", "tonumber", "math",
+ "type", "coroutine", "select", "error", "assert" }) do
+ sandbox_globals[k] = _G[k]
+ end
+ -- Complete its "globals"
+ sandbox_globals._G = sandbox_globals
+ -- And add in the magic function we need
+ sandbox_globals.go = sandboxed_go
+
+ local fn, globs = _wrap("return go()", "sandbox", sandbox_globals)
+ if not fn then
+ return 1
+ end
+
+ return fn()
+end
+
+return {
+ run = run,
+}