13
0

Explicitly sandbox Lua instances (3/4)

This allows UI scripts (saved in preferences) to access
os.* functions (non-sandboxed), while preventing other
scripts to do so.

Lua scripts that can run os commands can execute arbitrary
code on the system. While this is a nice feature, it can be
equally dangerous.
This commit is contained in:
Robin Gareus 2023-10-04 02:07:13 +02:00
parent 6b3f25eb2a
commit c1be897eed
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
9 changed files with 46 additions and 40 deletions

View File

@ -2350,12 +2350,11 @@ ARDOUR_UI::route_setup_info (const std::string& script_path)
return rv; return rv;
} }
LuaState lua; LuaState lua (true, true);
lua.Print.connect (&_lua_print); lua.Print.connect (&_lua_print);
lua.sandbox (true);
lua_State* L = lua.getState(); lua_State* L = lua.getState();
LuaInstance::register_classes (L); LuaInstance::register_classes (L, true);
LuaBindings::set_session (L, _session); LuaBindings::set_session (L, _session);
luabridge::push <PublicEditor *> (L, &PublicEditor::instance()); luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
lua_setglobal (L, "Editor"); lua_setglobal (L, "Editor");
@ -2403,12 +2402,11 @@ ARDOUR_UI::meta_route_setup (const std::string& script_path)
return; return;
} }
LuaState lua; LuaState lua (true, true);
lua.Print.connect (&_lua_print); lua.Print.connect (&_lua_print);
lua.sandbox (true);
lua_State* L = lua.getState(); lua_State* L = lua.getState();
LuaInstance::register_classes (L); LuaInstance::register_classes (L, true);
LuaBindings::set_session (L, _session); LuaBindings::set_session (L, _session);
luabridge::push <PublicEditor *> (L, &PublicEditor::instance()); luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
lua_setglobal (L, "Editor"); lua_setglobal (L, "Editor");
@ -2449,12 +2447,13 @@ ARDOUR_UI::meta_session_setup (const std::string& script_path)
return; return;
} }
LuaState lua; bool sandbox = UIConfiguration::instance().get_sandbox_all_lua_scripts ();
LuaState lua (true, sandbox);
lua.Print.connect (&_lua_print); lua.Print.connect (&_lua_print);
lua.sandbox (false);
lua_State* L = lua.getState(); lua_State* L = lua.getState();
LuaInstance::register_classes (L); LuaInstance::register_classes (L, sandbox);
LuaBindings::set_session (L, _session); LuaBindings::set_session (L, _session);
luabridge::push <PublicEditor *> (L, &PublicEditor::instance()); luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
lua_setglobal (L, "Editor"); lua_setglobal (L, "Editor");

View File

@ -941,11 +941,16 @@ Editor::trigger_script_by_name (const std::string script_name, const std::string
return; return;
} }
LuaState lua; #ifdef MIXBUS
bool sandbox = false; // mixer state save/reset/restore needs os.*
#else
bool sandbox = UIConfiguration::instance().get_sandbox_all_lua_scripts ();
#endif
LuaState lua (true, sandbox);
lua.Print.connect (&_lua_print); lua.Print.connect (&_lua_print);
lua.sandbox (false);
lua_State* L = lua.getState(); lua_State* L = lua.getState();
LuaInstance::register_classes (L); LuaInstance::register_classes (L, sandbox);
LuaBindings::set_session (L, _session); LuaBindings::set_session (L, _session);
luabridge::push <PublicEditor *> (L, &PublicEditor::instance()); luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
lua_setglobal (L, "Editor"); lua_setglobal (L, "Editor");

View File

@ -33,7 +33,7 @@ int main (int argc, char **argv)
{ {
#ifdef LUABINDINGDOC #ifdef LUABINDINGDOC
luabridge::setPrintBindings (true); luabridge::setPrintBindings (true);
LuaState lua; LuaState lua (false, false);
lua_State* L = lua.getState (); lua_State* L = lua.getState ();
#ifdef LUADOCOUT #ifdef LUADOCOUT
printf ("-- %s\n", ARDOUR::revision); printf ("-- %s\n", ARDOUR::revision);
@ -42,7 +42,7 @@ int main (int argc, char **argv)
printf ("[\n"); printf ("[\n");
printf ("{\"version\" : \"%s\"},\n\n", ARDOUR::revision); printf ("{\"version\" : \"%s\"},\n\n", ARDOUR::revision);
#endif #endif
LuaInstance::register_classes (L); LuaInstance::register_classes (L, false);
LuaInstance::register_hooks (L); LuaInstance::register_hooks (L);
ARDOUR::LuaBindings::dsp (L); ARDOUR::LuaBindings::dsp (L);
#ifdef LUADOCOUT #ifdef LUADOCOUT

View File

@ -778,7 +778,7 @@ LuaInstance::bind_dialog (lua_State* L)
} }
void void
LuaInstance::register_classes (lua_State* L) LuaInstance::register_classes (lua_State* L, bool sandbox)
{ {
LuaBindings::stddef (L); LuaBindings::stddef (L);
LuaBindings::common (L); LuaBindings::common (L);
@ -1100,15 +1100,7 @@ LuaInstance::register_classes (lua_State* L)
.addFunction ("config", &_ui_config) .addFunction ("config", &_ui_config)
.endNamespace () // end ArdourUI .endNamespace (); // end ArdourUI
.beginNamespace ("os")
#ifndef PLATFORM_WINDOWS
.addFunction ("execute", &lua_exec)
#endif
.addCFunction ("forkexec", &lua_forkexec)
.endNamespace ();
// Editing Symbols // Editing Symbols
#undef ZOOMFOCUS #undef ZOOMFOCUS
@ -1135,6 +1127,16 @@ LuaInstance::register_classes (lua_State* L)
.beginNamespace ("Editing") .beginNamespace ("Editing")
# include "editing_syms.h" # include "editing_syms.h"
.endNamespace (); .endNamespace ();
if (!sandbox) {
luabridge::getGlobalNamespace (L)
.beginNamespace ("os")
#ifndef PLATFORM_WINDOWS
.addFunction ("execute", &lua_exec)
#endif
.addCFunction ("forkexec", &lua_forkexec)
.endNamespace ();
}
} }
#undef xstr #undef xstr
@ -1174,6 +1176,7 @@ LuaInstance::destroy_instance ()
} }
LuaInstance::LuaInstance () LuaInstance::LuaInstance ()
: lua (true, UIConfiguration::instance().get_sandbox_all_lua_scripts ())
{ {
lua.Print.connect (&_lua_print); lua.Print.connect (&_lua_print);
init (); init ();
@ -1196,7 +1199,6 @@ LuaInstance::~LuaInstance ()
void void
LuaInstance::init () LuaInstance::init ()
{ {
lua.sandbox (false);
lua.do_command ( lua.do_command (
"function ScriptManager ()" "function ScriptManager ()"
" local self = { scripts = {}, instances = {}, icons = {} }" " local self = { scripts = {}, instances = {}, icons = {} }"
@ -1343,7 +1345,7 @@ LuaInstance::init ()
abort(); /*NOTREACHED*/ abort(); /*NOTREACHED*/
} }
register_classes (L); LuaInstance::register_classes (L, UIConfiguration::instance().get_sandbox_all_lua_scripts ());
register_hooks (L); register_hooks (L);
luabridge::push <PublicEditor *> (L, &PublicEditor::instance()); luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
@ -1527,8 +1529,8 @@ LuaInstance::pre_seed_script (std::string const& name, int& id)
if (spi) { if (spi) {
try { try {
std::string script = Glib::file_get_contents (spi->path); std::string script = Glib::file_get_contents (spi->path);
LuaState ls; LuaState ls (true, true);
register_classes (ls.getState ()); register_classes (ls.getState (), true);
LuaScriptParamList lsp = LuaScriptParams::script_params (ls, spi->path, "action_params"); LuaScriptParamList lsp = LuaScriptParams::script_params (ls, spi->path, "action_params");
LuaScriptParamPtr lspp (new LuaScriptParam("x-script-origin", "", spi->path, false, true)); LuaScriptParamPtr lspp (new LuaScriptParam("x-script-origin", "", spi->path, false, true));
lsp.push_back (lspp); lsp.push_back (lspp);
@ -1595,8 +1597,8 @@ LuaInstance::interactive_add (Gtk::Window& parent, LuaScriptInfo::ScriptType typ
return false; return false;
} }
LuaState ls; LuaState ls (true, true);
register_classes (ls.getState ()); register_classes (ls.getState (), true);
LuaScriptParamList lsp = LuaScriptParams::script_params (ls, spi->path, param_function); LuaScriptParamList lsp = LuaScriptParams::script_params (ls, spi->path, param_function);
/* allow cancel */ /* allow cancel */
@ -1865,9 +1867,8 @@ LuaInstance::register_lua_slot (const std::string& name, const std::string& scri
/* parse script, get ActionHook(s) from script */ /* parse script, get ActionHook(s) from script */
ActionHook ah; ActionHook ah;
try { try {
LuaState l; LuaState l (true, true);
l.Print.connect (&_lua_print); l.Print.connect (&_lua_print);
l.sandbox (true);
lua_State* L = l.getState(); lua_State* L = l.getState();
register_hooks (L); register_hooks (L);
l.do_command ("function ardour () end"); l.do_command ("function ardour () end");
@ -1972,6 +1973,7 @@ LuaCallback::LuaCallback (Session *s,
const ActionHook& ah, const ActionHook& ah,
const ARDOUR::LuaScriptParamList& args) const ARDOUR::LuaScriptParamList& args)
: SessionHandlePtr (s) : SessionHandlePtr (s)
, lua (true, UIConfiguration::instance().get_sandbox_all_lua_scripts ())
, _id ("0") , _id ("0")
, _name (name) , _name (name)
, _signals (ah) , _signals (ah)
@ -2005,6 +2007,7 @@ LuaCallback::LuaCallback (Session *s,
LuaCallback::LuaCallback (Session *s, XMLNode & node) LuaCallback::LuaCallback (Session *s, XMLNode & node)
: SessionHandlePtr (s) : SessionHandlePtr (s)
, lua (true, UIConfiguration::instance().get_sandbox_all_lua_scripts ())
{ {
XMLNode* child = NULL; XMLNode* child = NULL;
if (node.name() != X_("LuaCallback") if (node.name() != X_("LuaCallback")
@ -2088,7 +2091,6 @@ void
LuaCallback::init (void) LuaCallback::init (void)
{ {
lua.Print.connect (&_lua_print); lua.Print.connect (&_lua_print);
lua.sandbox (false);
lua.do_command ( lua.do_command (
"function ScriptManager ()" "function ScriptManager ()"
@ -2209,7 +2211,7 @@ LuaCallback::init (void)
abort(); /*NOTREACHED*/ abort(); /*NOTREACHED*/
} }
LuaInstance::register_classes (L); LuaInstance::register_classes (L, UIConfiguration::instance().get_sandbox_all_lua_scripts ());
LuaInstance::register_hooks (L); LuaInstance::register_hooks (L);
luabridge::push <PublicEditor *> (L, &PublicEditor::instance()); luabridge::push <PublicEditor *> (L, &PublicEditor::instance());

View File

@ -112,7 +112,7 @@ public:
static void destroy_instance(); static void destroy_instance();
~LuaInstance(); ~LuaInstance();
static void register_classes (lua_State* L); static void register_classes (lua_State* L, bool sandbox);
static void register_hooks (lua_State* L); static void register_hooks (lua_State* L);
static void bind_cairo (lua_State* L); static void bind_cairo (lua_State* L);
static void bind_dialog (lua_State* L); static void bind_dialog (lua_State* L);

View File

@ -197,12 +197,11 @@ void LuaWindow::reinit_lua ()
{ {
ENSURE_GUI_THREAD (*this, &LuaWindow::session_going_away); ENSURE_GUI_THREAD (*this, &LuaWindow::session_going_away);
delete lua; delete lua;
lua = new LuaState(); lua = new LuaState (true, UIConfiguration::instance().get_sandbox_all_lua_scripts ());
lua->Print.connect (sigc::mem_fun (*this, &LuaWindow::append_text)); lua->Print.connect (sigc::mem_fun (*this, &LuaWindow::append_text));
lua->sandbox (false);
lua_State* L = lua->getState(); lua_State* L = lua->getState();
LuaInstance::register_classes (L); LuaInstance::register_classes (L, UIConfiguration::instance().get_sandbox_all_lua_scripts ());
luabridge::push <PublicEditor *> (L, &PublicEditor::instance()); luabridge::push <PublicEditor *> (L, &PublicEditor::instance());
lua_setglobal (L, "Editor"); lua_setglobal (L, "Editor");
} }

View File

@ -1869,6 +1869,7 @@ ProcessorEntry::PluginInlineDisplay::display_frame (cairo_t* cr, double w, doubl
ProcessorEntry::LuaPluginDisplay::LuaPluginDisplay (ProcessorEntry& e, std::shared_ptr<ARDOUR::LuaProc> p, uint32_t max_height) ProcessorEntry::LuaPluginDisplay::LuaPluginDisplay (ProcessorEntry& e, std::shared_ptr<ARDOUR::LuaProc> p, uint32_t max_height)
: PluginInlineDisplay (e, p, max_height) : PluginInlineDisplay (e, p, max_height)
, _luaproc (p) , _luaproc (p)
, lua_gui (true, true)
, _lua_render_inline (0) , _lua_render_inline (0)
{ {
p->setup_lua_inline_gui (&lua_gui); p->setup_lua_inline_gui (&lua_gui);

View File

@ -189,8 +189,7 @@ SessionDialog::meta_master_bus_profile (std::string script_path)
return UINT32_MAX; return UINT32_MAX;
} }
LuaState lua; LuaState lua (true, true);
lua.sandbox (true);
lua_State* L = lua.getState(); lua_State* L = lua.getState();
lua.do_command ( lua.do_command (

View File

@ -155,6 +155,7 @@ UI_CONFIG_VARIABLE (bool, ask_cut_copy_section_tempo_map, "ask-cut-copy-section-
UI_CONFIG_VARIABLE (std::string, freesound_dir, "freesound-dir", "") UI_CONFIG_VARIABLE (std::string, freesound_dir, "freesound-dir", "")
UI_CONFIG_VARIABLE (int, max_note_height, "max-note-height", 20) UI_CONFIG_VARIABLE (int, max_note_height, "max-note-height", 20)
UI_CONFIG_VARIABLE (bool, prefer_tap_tempo, "prefer-tap-tempo", false) UI_CONFIG_VARIABLE (bool, prefer_tap_tempo, "prefer-tap-tempo", false)
UI_CONFIG_VARIABLE (bool, sandbox_all_lua_scripts, "sandbox-all-lua-scripts", false)
/* these are visibility-type selections in the New Track dialog that we should make persistent for the user's choices */ /* these are visibility-type selections in the New Track dialog that we should make persistent for the user's choices */
UI_CONFIG_VARIABLE (bool, show_on_cue_page, "show-on-cue-page", true) UI_CONFIG_VARIABLE (bool, show_on_cue_page, "show-on-cue-page", true)