Skip to content

Commit 7f5d052

Browse files
author
James Roseborough
committed
Add samplesandboxed.lua script to demonstrate sandboxing in lua.
1 parent b16c521 commit 7f5d052

File tree

3 files changed

+118
-2
lines changed

3 files changed

+118
-2
lines changed

README.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -980,7 +980,8 @@ <h2>Main Changes by Version</h2>
980980
<li>Improve garbage collection of orphaned coroutines when yielding from debug hook functions (fixes issue #32).</li>
981981
<li>LuaScriptEngineFactory.getScriptEngine() now returns new instance of LuaScriptEngine for each call.</li>
982982
<li>Fix os.date("*t") to return hour in 24 hour format (fixes issue #45)</li>
983-
<li>Add SampleSandboxed.java sample code to illustrate sandboxing techniques.</li>
983+
<li>Add SampleSandboxed.java example code to illustrate sandboxing techniques in Java.</li>
984+
<li>Add samplesandboxed.lua example code to illustrate sandboxing techniques in lua.</li>
984985
<li>Make string metatable a proper metatable, and make it read-only by default.</li>
985986
<li>Add sample code that illustrates techniques in creating sandboxed environments.</li>
986987
<li>Add convenience methods to Global to load string scripts with custom environment.</li>

examples/jse/SampleSandboxed.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
* in a server environment.
88
*
99
* <p>Although this sandboxing is done primarily in Java here, these
10-
* same techniques should all be possible directly from lua using metatables.
10+
* same techniques should all be possible directly from lua using metatables,
11+
* and examples are shown in examples/lua/samplesandboxed.lua.
1112
*
1213
* <p> The main goals of this sandbox are:
1314
* <ul>

examples/lua/samplesandboxed.lua

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
-- Illustration of simple sandboxing techniques that can be used in luaj.
2+
--
3+
-- This sandboxing is done in lua. These same techniques are all
4+
-- possible directly from Java, as shown in /examples/jse/SampleSandboxed.java.
5+
--
6+
-- The main goals of this sandbox are:
7+
-- * lightweight sandbox controlled by single lua script
8+
-- * use new globals per-script and leave out dangerous libraries
9+
-- * use debug hook functions with yield to limit lua scripts
10+
-- * use read-only tables to protect shared metatables
11+
12+
-- Replace the string metatable with a read-only version.
13+
debug.setmetatable('', {
14+
__index = string,
15+
__newindex = function() error('table is read only') end,
16+
__metatable = false,
17+
})
18+
19+
-- Duplicate contents of a table.
20+
local function dup(table)
21+
local t = {}
22+
for k,v in pairs(table) do t[k] = v end
23+
return t
24+
end
25+
26+
-- Produce a new user environment.
27+
-- Only a subset of functionality is exposed.
28+
-- Must not expose debug, luajava, or other easily abused functions.
29+
local function new_user_globals()
30+
local g = {
31+
print = print,
32+
pcall = pcall,
33+
xpcall = xpcall,
34+
pairs = pairs,
35+
ipairs = ipairs,
36+
getmetatable = getmetatable,
37+
setmetatable = setmetatable,
38+
load = load,
39+
package = { preload = {}, loaded = {}, },
40+
table = dup(table),
41+
string = dup(string),
42+
math = dup(math),
43+
bit32 = dup(bit32),
44+
-- functions can also be customized here
45+
}
46+
g._G = g
47+
return g
48+
end
49+
50+
-- Run a script in it's own user environment,
51+
-- and limit it to a certain number of cycles before abandoning it.
52+
local function run_user_script_in_sandbox(script)
53+
do
54+
-- load the chunk using the main globals for the environment
55+
-- initially so debug hooks will be usable in these threads.
56+
local chunk, err = _G.load(script, 'main', 't')
57+
if not chunk then
58+
print('error loading', err, script)
59+
return
60+
end
61+
62+
-- set the user environment to user-specific globals.
63+
-- these must not contain debug, luajava, coroutines, or other
64+
-- dangerous functionality.
65+
local user_globals = new_user_globals()
66+
debug.setupvalue(chunk, 1, user_globals)
67+
68+
-- run the thread for a specific number of cycles.
69+
-- when it yields out, abandon it.
70+
local thread = coroutine.create(chunk)
71+
local hook = function() coroutine.yield('resource used too many cycles') end
72+
debug.sethook(thread, hook, '', 40)
73+
local errhook = function(msg) print("in error hook", msg); return msg; end
74+
print(script, xpcall(coroutine.resume, errhook, thread))
75+
end
76+
77+
-- run garbage collection to clean up orphaned threads
78+
collectgarbage()
79+
end
80+
81+
-- Tun various test scripts that should succeed.
82+
run_user_script_in_sandbox( "return 'foo'" )
83+
run_user_script_in_sandbox( "return ('abc'):len()" )
84+
run_user_script_in_sandbox( "return getmetatable('abc')" )
85+
run_user_script_in_sandbox( "return getmetatable('abc').len" )
86+
run_user_script_in_sandbox( "return getmetatable('abc').__index" )
87+
88+
-- Example user scripts that attempt rogue operations, and will fail.
89+
run_user_script_in_sandbox( "return setmetatable('abc', {})" )
90+
run_user_script_in_sandbox( "getmetatable('abc').len = function() end" )
91+
run_user_script_in_sandbox( "getmetatable('abc').__index = {}" )
92+
run_user_script_in_sandbox( "getmetatable('abc').__index.x = 1" )
93+
run_user_script_in_sandbox( "while true do print('loop') end" )
94+
95+
-- Example use of other shared metatables, which should also be made read-only.
96+
-- this toy example allows booleans to be added to numbers.
97+
98+
-- Normally boolean cannot participate in arithmetic.
99+
local number_script = "return 2 + 7, 2 + true, false + 7"
100+
run_user_script_in_sandbox(number_script)
101+
102+
-- Create a shared metatable that includes addition for booleans.
103+
-- This would only be set up by the server, not by client scripts.
104+
debug.setmetatable(true, {
105+
__newindex = function() error('table is read only') end,
106+
__metatable = false,
107+
__add = function(a, b)
108+
return (a == true and 1 or a == false and 0 or a) +
109+
(b == true and 1 or b == false and 0 or b)
110+
end
111+
})
112+
113+
-- All user scripts will now get addition involving booleans.
114+
run_user_script_in_sandbox(number_script)

0 commit comments

Comments
 (0)