mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2026-05-05 20:38:03 +02:00
wplua: add flags to modify the sandbox behavior
with ISOLATE_ENV, it isolates the global environment between scripts just like it did before; without it, it uses a common environment with MINIMAL_STD, it restricts even further the available library functions; useful for configuration files that don't need to do actual scripting, just to define some tables
This commit is contained in:
parent
cb228637d6
commit
94d527e187
4 changed files with 124 additions and 36 deletions
|
|
@ -8,30 +8,9 @@
|
|||
--
|
||||
-- SPDX-License-Identifier: MIT
|
||||
|
||||
SANDBOX_ENV_LIST = {}
|
||||
local SANDBOX_ENV = {}
|
||||
|
||||
-- List of safe functions and packages
|
||||
([[
|
||||
|
||||
_VERSION assert error ipairs next pairs
|
||||
pcall select tonumber tostring type xpcall
|
||||
|
||||
table utf8
|
||||
|
||||
math.abs math.acos math.asin math.atan math.ceil
|
||||
math.cos math.deg math.exp math.tointeger math.floor math.fmod
|
||||
math.huge math.ult math.log math.maxinteger math.mininteger math.max
|
||||
math.min math.modf math.pi math.rad math.random
|
||||
math.sin math.sqrt math.tan math.type
|
||||
|
||||
string.byte string.char string.find string.format string.gmatch
|
||||
string.gsub string.len string.lower string.match string.reverse
|
||||
string.sub string.upper
|
||||
|
||||
os.clock os.difftime os.time os.date os.getenv
|
||||
|
||||
]]):gsub('%S+', function(id)
|
||||
local function populate_env(id)
|
||||
local module, method = id:match('([^%.]+)%.([^%.]+)')
|
||||
if module then
|
||||
SANDBOX_ENV[module] = SANDBOX_ENV[module] or {}
|
||||
|
|
@ -39,7 +18,43 @@ local SANDBOX_ENV = {}
|
|||
else
|
||||
SANDBOX_ENV[id] = _G[id]
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- List of safe functions and packages
|
||||
if SANDBOX_CONFIG["minimal_std"] then
|
||||
-- minimal list, used for config files
|
||||
([[
|
||||
_VERSION ipairs pairs select tonumber tostring type
|
||||
|
||||
table
|
||||
|
||||
string.byte string.char string.find string.format string.gmatch
|
||||
string.gsub string.len string.lower string.match string.reverse
|
||||
string.sub string.upper
|
||||
|
||||
]]):gsub('%S+', populate_env)
|
||||
else
|
||||
-- full list, used for scripts
|
||||
([[
|
||||
_VERSION assert error ipairs next pairs
|
||||
pcall select tonumber tostring type xpcall
|
||||
|
||||
table utf8
|
||||
|
||||
math.abs math.acos math.asin math.atan math.ceil
|
||||
math.cos math.deg math.exp math.tointeger math.floor math.fmod
|
||||
math.huge math.ult math.log math.maxinteger math.mininteger math.max
|
||||
math.min math.modf math.pi math.rad math.random
|
||||
math.sin math.sqrt math.tan math.type
|
||||
|
||||
string.byte string.char string.find string.format string.gmatch
|
||||
string.gsub string.len string.lower string.match string.reverse
|
||||
string.sub string.upper
|
||||
|
||||
os.clock os.difftime os.time os.date os.getenv
|
||||
|
||||
]]):gsub('%S+', populate_env)
|
||||
end
|
||||
|
||||
-- Additionally export everything in SANDBOX_EXPORT
|
||||
if type(SANDBOX_EXPORT) == "table" then
|
||||
|
|
@ -60,16 +75,36 @@ for k, v in pairs(SANDBOX_ENV) do
|
|||
end
|
||||
end
|
||||
|
||||
function sandbox(chunk)
|
||||
if SANDBOX_CONFIG["isolate_env"] then
|
||||
-- in isolate_env mode, use a separate enviornment for each loaded chunk and
|
||||
-- store all of them in a global table so that they are not garbage collected
|
||||
SANDBOX_ENV_LIST = {}
|
||||
|
||||
function sandbox(chunk)
|
||||
-- chunk's environment will be an empty table with __index
|
||||
-- to access our SANDBOX_ENV (without being able to write it)
|
||||
local env = setmetatable({}, {
|
||||
__index = SANDBOX_ENV,
|
||||
})
|
||||
-- store the chunk's environment so that it is not garbage collected
|
||||
table.insert(SANDBOX_ENV_LIST, env)
|
||||
-- set it as the chunk's 1st upvalue (__ENV)
|
||||
debug.setupvalue(chunk, 1, env)
|
||||
-- execute the chunk
|
||||
chunk()
|
||||
end
|
||||
else
|
||||
-- in common_env mode, use the same environment for all loaded chunks
|
||||
-- chunk's environment will be an empty table with __index
|
||||
-- to access our SANDBOX_ENV (without being able to write it)
|
||||
local env = setmetatable({}, {
|
||||
SANDBOX_COMMON_ENV = setmetatable({}, {
|
||||
__index = SANDBOX_ENV,
|
||||
})
|
||||
-- set it as the chunk's 1st upvalue (__ENV)
|
||||
debug.setupvalue(chunk, 1, env)
|
||||
-- store the chunk's environment so that it is not garbage collected
|
||||
table.insert(SANDBOX_ENV_LIST, env)
|
||||
-- execute the chunk
|
||||
chunk()
|
||||
|
||||
function sandbox(chunk)
|
||||
-- set it as the chunk's 1st upvalue (__ENV)
|
||||
debug.setupvalue(chunk, 1, SANDBOX_COMMON_ENV)
|
||||
-- execute the chunk
|
||||
chunk()
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -115,10 +115,20 @@ wplua_free (lua_State * L)
|
|||
}
|
||||
|
||||
void
|
||||
wplua_enable_sandbox (lua_State * L)
|
||||
wplua_enable_sandbox (lua_State * L, WpLuaSandboxFlags flags)
|
||||
{
|
||||
g_autoptr (GError) error = NULL;
|
||||
wp_debug ("enabling Lua sandbox");
|
||||
|
||||
lua_newtable (L);
|
||||
lua_pushliteral (L, "minimal_std");
|
||||
lua_pushboolean (L, (flags & WP_LUA_SANDBOX_MINIMAL_STD));
|
||||
lua_settable (L, -3);
|
||||
lua_pushliteral (L, "isolate_env");
|
||||
lua_pushboolean (L, (flags & WP_LUA_SANDBOX_ISOLATE_ENV));
|
||||
lua_settable (L, -3);
|
||||
lua_setglobal (L, "SANDBOX_CONFIG");
|
||||
|
||||
if (!wplua_load_uri (L, URI_SANDBOX, &error)) {
|
||||
wp_critical ("Failed to load sandbox: %s", error->message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,11 +39,15 @@ typedef enum {
|
|||
WP_LUA_ERROR_RUNTIME,
|
||||
} WpLuaError;
|
||||
|
||||
typedef enum {
|
||||
WP_LUA_SANDBOX_MINIMAL_STD,
|
||||
WP_LUA_SANDBOX_ISOLATE_ENV,
|
||||
} WpLuaSandboxFlags;
|
||||
|
||||
lua_State * wplua_new (void);
|
||||
void wplua_free (lua_State * L);
|
||||
|
||||
void wplua_enable_sandbox (lua_State * L);
|
||||
void wplua_enable_sandbox (lua_State * L, WpLuaSandboxFlags flags);
|
||||
|
||||
void wplua_register_type_methods (lua_State * L, GType type,
|
||||
lua_CFunction constructor, const luaL_Reg * methods);
|
||||
|
|
|
|||
|
|
@ -404,7 +404,7 @@ test_wplua_signals ()
|
|||
}
|
||||
|
||||
static void
|
||||
test_wplua_sandbox ()
|
||||
test_wplua_sandbox_script ()
|
||||
{
|
||||
g_autoptr (GError) error = NULL;
|
||||
lua_State *L = wplua_new ();
|
||||
|
|
@ -420,7 +420,7 @@ test_wplua_sandbox ()
|
|||
wplua_load_buffer (L, code, sizeof (code) - 1, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
wplua_enable_sandbox (L);
|
||||
wplua_enable_sandbox (L, WP_LUA_SANDBOX_ISOLATE_ENV);
|
||||
|
||||
const gchar code2[] =
|
||||
"o = TestObject_new()\n";
|
||||
|
|
@ -464,6 +464,44 @@ test_wplua_sandbox ()
|
|||
wplua_free (L);
|
||||
}
|
||||
|
||||
static void
|
||||
test_wplua_sandbox_config ()
|
||||
{
|
||||
g_autoptr (GError) error = NULL;
|
||||
lua_State *L = wplua_new ();
|
||||
|
||||
wplua_enable_sandbox (L, WP_LUA_SANDBOX_MINIMAL_STD);
|
||||
|
||||
const gchar code3[] =
|
||||
"o = { answer = 42 }\n";
|
||||
wplua_load_buffer (L, code3, sizeof (code3) - 1, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
/* no assert() in minimal_std mode, resort to other means of failure */
|
||||
const gchar code4[] =
|
||||
"if (o.answer ~= 42) then\n"
|
||||
" non_existent_function()\n"
|
||||
"end\n";
|
||||
wplua_load_buffer (L, code4, sizeof (code4) - 1, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
/* string.* is protected */
|
||||
const gchar code6[] =
|
||||
"string.test = 'hello world'\n";
|
||||
wplua_load_buffer (L, code6, sizeof (code6) - 1, &error);
|
||||
g_debug ("expected error: %s", error ? error->message : "null");
|
||||
g_assert_error (error, WP_DOMAIN_LUA, WP_LUA_ERROR_RUNTIME);
|
||||
g_clear_error (&error);
|
||||
|
||||
/* this would be an error if the assert function was exported, but it's not */
|
||||
const gchar code7[] =
|
||||
"assert = 'hello world'\n";
|
||||
wplua_load_buffer (L, code7, sizeof (code7) - 1, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
wplua_free (L);
|
||||
}
|
||||
|
||||
gint
|
||||
main (gint argc, gchar *argv[])
|
||||
{
|
||||
|
|
@ -475,7 +513,8 @@ main (gint argc, gchar *argv[])
|
|||
g_test_add_func ("/wplua/properties", test_wplua_properties);
|
||||
g_test_add_func ("/wplua/closure", test_wplua_closure);
|
||||
g_test_add_func ("/wplua/signals", test_wplua_signals);
|
||||
g_test_add_func ("/wplua/sandbox", test_wplua_sandbox);
|
||||
g_test_add_func ("/wplua/sandbox/script", test_wplua_sandbox_script);
|
||||
g_test_add_func ("/wplua/sandbox/config", test_wplua_sandbox_config);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue