diff options
Diffstat (limited to 'lib/supple/sandbox.lua')
-rw-r--r-- | lib/supple/sandbox.lua | 128 |
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, +} |