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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
-- lib/supple/host.lua
--
-- Sandbox (for) Untrusted Procedure Partitioning (in) Lua Engine
--
-- Management of the host side of Supple
--
-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org>
--
-- For licence terms, see COPYING
--
local luxio = require 'luxio'
local subprocess = require 'luxio.subprocess'
local comms = require 'supple.comms'
local objects = require 'supple.objects'
local capi = require 'supple.capi'
local hostname = "host"
local counter = 0
local limits, globals
local function simplify(t, memo)
if not memo then memo = {} end
if memo[t] then return memo[t] end
local ret = {}
memo[t] = ret
local kk, vv
for k, v in capi.pairs(t) do
kk, vv = k, v
if capi.type(k) == "table" then
kk = simplify(k, memo)
end
if capi.type(v) == "table" then
vv = simplify(v, memo)
end
if capi.rawtype(kk) ~= "userdata" and
capi.rawtype(vv) ~= "userdata" then
-- We've not got a proxy left over anywhere, so copy it
ret[kk] = vv
end
end
return ret
end
local function run_wrapper()
local wrapperpath = "@@WRAPPER_BIN@@"
-- START_TEST_SUPPLE
wrapperpath = "./testwrapper"
-- END_TEST_SUPPLE
local fds = {}
local ret, errno = luxio.socketpair(luxio.AF_UNIX, luxio.SOCK_STREAM,
luxio.PF_UNIX, fds)
if ret ~= 0 then
error("Unable to launch subprocess, could not prepare socketpair():"
.. luxio.strerror(errno))
end
local proc, msg = subprocess.spawn {
"supple-sandbox",
exe = wrapperpath,
stdin = fds[1],
stdout = -1,
stderr = -1,
close_in_child = { fds[1], fds[2] },
}
if not proc then
error(msg)
end
luxio.close(fds[1])
return proc, fds[2]
end
local function run_sandbox(codestr, codename, ...)
-- Prepare and start a sandbox,
-- compiling the codestr and running it
-- with the given args
local child, commsfd = run_wrapper()
counter = counter + 1
objects.set_name(("host[%d,%%d]"):format(counter))
comms._set_fd(commsfd)
objects.set_proc_call(comms.call)
local func, env = comms.call("supple:loadstring", "__call", codestr, codename)
if not func then
error(env)
end
local limitsok, limitserr = true
if limits then
limitsok, limitserr = comms.call("supple:set_limits", "__call", limits)
end
-- In a protected manner, capture the output of the call
local args, ret = {...}
local function capture()
ret = {func(unpack(args))}
end
local ok, err
if limitsok then
if globals then
-- Hand over the globals
for k, v in pairs(globals) do
env[k] = v
end
end
ok, err = pcall(capture)
else
ok, err = limitsok, limitserr
end
-- Convert any complex objects returned to us, so we can clean up...
if ok then
ret = simplify(ret)
end
-- We need to clean up, so dump all the objects
func = nil
env = nil
-- And ask the supple API to clear down too
objects.clean_down(true)
comms._set_fd(-1)
luxio.kill(child.pid, luxio.SIGKILL)
child:wait()
if ok then
return ok, unpack(ret)
else
return ok, err
end
end
local function sandboxed_loadstring(codestr, codename)
return comms.call("supple:loadstring", "__call", codestr, codename)
end
local function set_hostname(newname)
hostname = newname
counter = 0
end
local function set_limits(newlimits)
limits = newlimits
end
local function set_globals(newglobals)
globals = newglobals
end
return {
run = run_sandbox,
loadstring = sandboxed_loadstring,
set_name = set_hostname,
set_limits = set_limits,
set_globals = set_globals,
}
|