1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
-- 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 objects = require 'supple.objects'
local comms = require 'supple.comms'
local luxio = require 'luxio'
local sio = require 'luxio.simple'
local loadstring = loadstring
local load = load
local setfenv = setfenv
-- 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)
globs = globs or {}
local fn_glob = setmetatable({}, { __index = globs, __metatable=true })
local fn_ret, msg
assert(fn, "No function/source provided?")
assert(src, "No source name provided?")
if setfenv then
-- Lua 5.1 style load...
fn_ret, msg = ((capi.rawtype(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 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 = {
type = capi.type,
}
for _, k in ipairs({ "table", "string", "pairs", "ipairs", "pcall",
"xpcall", "unpack", "tostring", "tonumber", "math",
"coroutine", "select", "error", "assert" }) do
sandbox_globals[k] = _G[k]
end
-- Complete its "globals"
sandbox_globals._G = sandbox_globals
local _go_str = [[
return ({...})[1]()
]]
local fn, globs = _wrap(_go_str, "sandbox", sandbox_globals)
if not fn then
return 1
end
objects.set_name(("supple-sandbox[%d]"):format(luxio.getpid()))
objects.set_proc_call(comms.call)
local function wrappered_load(str, name)
return _wrap(str, name, sandbox_globals)
end
-- Pretend we've "given" the host an object called 'supple:loadstring'
-- which is the loadstring/load function
objects.give(wrappered_load, "supple:loadstring")
objects.give(objects.clean_down, "supple:clean_down")
comms._set_fd(0)
return fn(comms._wait)
end
return {
run = run,
}
|