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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
|
-- example/simple-example.lua
--
-- Sandbox (for) Untrusted Procedure Partitioning (in) Lua Engine
--
-- Simple example
--
-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org>
--
-- For licence terms, see COPYING
--
supple = require'supple'
luxio = require'luxio'
-- Code string to run in the untrusted environment
subcode = [[
local t = ...
local tot = 0
for i = 1, #t do
tot = tot + t[i]()
end
t.tot = tot
return tot, -t
]]
-- Generate a function to return 'n'
local function give_n(n)
return function() return n end
end
-- A useful table for the test
local tab = {
give_n(4),
give_n(8),
give_n(12),
}
-- A metatable which defines -tab to equal 'JEFF'
local mt = {
__unm = function () return "JEFF" end
}
setmetatable(tab, mt)
local tests, passed = 0, 0
local function lprint(expect, result, ...)
tests = tests + 1
luxio.write(1, ("[%d]\r"):format(tests))
local foo = {n=select("#",...),...}
if expect and not result then
print "Want OK, got FAIL"
elseif (not expect) and result then
print "Want FAIL, got OK"
end
if expect ~= result then
for i = 1, foo.n do
if type(foo[i]) == "table" then
print("{")
for k, v in pairs(foo[i]) do
print("",k,v)
end
print("}")
else
print(foo[i])
end
end
print()
else
passed = passed + 1
end
end
local function lprint_ok(...)
return lprint(true, ...)
end
local function lprint_fail(...)
return lprint(false, ...)
end
-- Finally, run the subcode
lprint_ok(supple.host.run(subcode, "@test-code", tab))
assert(tab.tot == 24)
-- Now run a supple command which we expect to error out.
lprint_fail(supple.host.run("unknown()", "@test-code"))
-- And now, one where we pass an error from host to sandbox and back
lprint_fail(supple.host.run("local f = ... f()", "@test-code", function() unknown() end))
-- And now, one where we pass an error from sandbox to host to sandbox and back
lprint_fail(supple.host.run("local f = ... f(function() unknown() end)", "@test-code", function(ff) ff() end))
-- Next , a reasonable traceback via named functions on each end...
local errsrc = [[
function raises()
does_not_exist()
end
function passes()
raises()
end
function chains(f)
f(passes)
end
local callme = ...
callme(chains)
]]
function loopback(f)
f(loopback)
end
lprint_fail(supple.host.run(errsrc, "@error-code", loopback))
-- Now we try the sandboxing limits
local long_run = [[
local s = ""
for i = 1, 100000 do
s = s .. "FISHFISHFISHFISHFISH"
end
return #s
]]
supple.host.set_limits { count = 100 }
lprint_fail(supple.host.run(long_run, "@long-code"))
supple.host.set_limits { memory = 1000 }
lprint_fail(supple.host.run(long_run, "@big-code"))
-- next we demonstrate that ipairs works on proxied tables
local summing = [[
local t = ...
local tot = 0
for i, v in ipairs(t) do
tot = tot + v
end
return tot
]]
lprint_ok(supple.host.run(summing, "@summing", { 10, 14, 3 }))
-- next we demonstrate that next works on proxied tables
local isempty = [[
local t = ...
return next(t) == nil
]]
lprint_ok(supple.host.run(isempty, "@isempty", {}))
lprint_ok(supple.host.run(isempty, "@isempty", {"bar"}))
-- And now that pairs works on proxied tables
local keys = [[
local t = ...
local ret = {}
for k, v in pairs(t) do
ret[#ret+1] = k
end
ret.ret = ret
return ret
]]
lprint_ok(supple.host.run(keys, "@keys", { foo="bar", baz="meta" }))
-- Next demonstrate that using supple.host.loadstring works to allow
-- globals set in the parent to be seen/changed
local function loader(n)
return supple.host.loadstring(([[return { print=print, name = %q }]]):format(n), "@" .. n)
end
local getname = [[
local f = ...
local mod = (f("Jeff"))()
return mod.print and "PRINT" or mod.name
]]
-- Expect to see 'PRINT'
lprint_ok(supple.host.run(getname, "@getname", loader))
-- Attempt to do a test which shows the same issue as seen with gitano-web
local updates = {
["refs/heads/master"] = {
oldsha = "0123456789abcdef0123456789abcdef01234567",
newsha = "76543210fedcba9876543210fedcba9876543210",
}
}
local update_code = [[
local repo, updates = ...
local hadmaster = false
local foundrefs = {}
if updates["refs/heads/master"] then
hadmaster = true
end
for ref, data in pairs(updates) do
foundrefs[ref] = { data.oldsha, data.newsha }
end
return hadmaster, foundrefs
]]
for i = 1, 1000 do
supple.track.start()
local ok, res = pcall(supple.host.run, update_code, "@update-hook", "REPO", updates)
if not ok then print(res) print(supple.track.stop()) end
lprint_ok(ok)
lprint_ok(res)
supple.track.stop()
if passed ~= tests then
os.exit(1)
end
end
print(("[%d/%d OK]"):format(passed, tests))
-- Dump the final trace, just for edification
--print(supple.track.stop())
|