From c1be897eed25b4fa22ba09e304f0295e95f4a359 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Wed, 4 Oct 2023 02:07:13 +0200 Subject: [PATCH] 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. --- gtk2_ardour/ardour_ui.cc | 17 +++++++------- gtk2_ardour/editor_actions.cc | 11 ++++++--- gtk2_ardour/luadoc.cc | 4 ++-- gtk2_ardour/luainstance.cc | 42 ++++++++++++++++++----------------- gtk2_ardour/luainstance.h | 2 +- gtk2_ardour/luawindow.cc | 5 ++--- gtk2_ardour/processor_box.cc | 1 + gtk2_ardour/session_dialog.cc | 3 +-- gtk2_ardour/ui_config_vars.h | 1 + 9 files changed, 46 insertions(+), 40 deletions(-) diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 2cd247d6cd..3713af741c 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -2350,12 +2350,11 @@ ARDOUR_UI::route_setup_info (const std::string& script_path) return rv; } - LuaState lua; + LuaState lua (true, true); lua.Print.connect (&_lua_print); - lua.sandbox (true); lua_State* L = lua.getState(); - LuaInstance::register_classes (L); + LuaInstance::register_classes (L, true); LuaBindings::set_session (L, _session); luabridge::push (L, &PublicEditor::instance()); lua_setglobal (L, "Editor"); @@ -2403,12 +2402,11 @@ ARDOUR_UI::meta_route_setup (const std::string& script_path) return; } - LuaState lua; + LuaState lua (true, true); lua.Print.connect (&_lua_print); - lua.sandbox (true); lua_State* L = lua.getState(); - LuaInstance::register_classes (L); + LuaInstance::register_classes (L, true); LuaBindings::set_session (L, _session); luabridge::push (L, &PublicEditor::instance()); lua_setglobal (L, "Editor"); @@ -2449,12 +2447,13 @@ ARDOUR_UI::meta_session_setup (const std::string& script_path) return; } - LuaState lua; + bool sandbox = UIConfiguration::instance().get_sandbox_all_lua_scripts (); + + LuaState lua (true, sandbox); lua.Print.connect (&_lua_print); - lua.sandbox (false); lua_State* L = lua.getState(); - LuaInstance::register_classes (L); + LuaInstance::register_classes (L, sandbox); LuaBindings::set_session (L, _session); luabridge::push (L, &PublicEditor::instance()); lua_setglobal (L, "Editor"); diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc index 9d0f44189d..3314b4ecf8 100644 --- a/gtk2_ardour/editor_actions.cc +++ b/gtk2_ardour/editor_actions.cc @@ -941,11 +941,16 @@ Editor::trigger_script_by_name (const std::string script_name, const std::string 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.sandbox (false); lua_State* L = lua.getState(); - LuaInstance::register_classes (L); + LuaInstance::register_classes (L, sandbox); LuaBindings::set_session (L, _session); luabridge::push (L, &PublicEditor::instance()); lua_setglobal (L, "Editor"); diff --git a/gtk2_ardour/luadoc.cc b/gtk2_ardour/luadoc.cc index d2085b8753..f700869e79 100644 --- a/gtk2_ardour/luadoc.cc +++ b/gtk2_ardour/luadoc.cc @@ -33,7 +33,7 @@ int main (int argc, char **argv) { #ifdef LUABINDINGDOC luabridge::setPrintBindings (true); - LuaState lua; + LuaState lua (false, false); lua_State* L = lua.getState (); #ifdef LUADOCOUT printf ("-- %s\n", ARDOUR::revision); @@ -42,7 +42,7 @@ int main (int argc, char **argv) printf ("[\n"); printf ("{\"version\" : \"%s\"},\n\n", ARDOUR::revision); #endif - LuaInstance::register_classes (L); + LuaInstance::register_classes (L, false); LuaInstance::register_hooks (L); ARDOUR::LuaBindings::dsp (L); #ifdef LUADOCOUT diff --git a/gtk2_ardour/luainstance.cc b/gtk2_ardour/luainstance.cc index 7913c8c652..70ddcac4c6 100644 --- a/gtk2_ardour/luainstance.cc +++ b/gtk2_ardour/luainstance.cc @@ -778,7 +778,7 @@ LuaInstance::bind_dialog (lua_State* L) } void -LuaInstance::register_classes (lua_State* L) +LuaInstance::register_classes (lua_State* L, bool sandbox) { LuaBindings::stddef (L); LuaBindings::common (L); @@ -1100,15 +1100,7 @@ LuaInstance::register_classes (lua_State* L) .addFunction ("config", &_ui_config) - .endNamespace () // end ArdourUI - - .beginNamespace ("os") -#ifndef PLATFORM_WINDOWS - .addFunction ("execute", &lua_exec) -#endif - .addCFunction ("forkexec", &lua_forkexec) - .endNamespace (); - + .endNamespace (); // end ArdourUI // Editing Symbols #undef ZOOMFOCUS @@ -1135,6 +1127,16 @@ LuaInstance::register_classes (lua_State* L) .beginNamespace ("Editing") # include "editing_syms.h" .endNamespace (); + + if (!sandbox) { + luabridge::getGlobalNamespace (L) + .beginNamespace ("os") +#ifndef PLATFORM_WINDOWS + .addFunction ("execute", &lua_exec) +#endif + .addCFunction ("forkexec", &lua_forkexec) + .endNamespace (); + } } #undef xstr @@ -1174,6 +1176,7 @@ LuaInstance::destroy_instance () } LuaInstance::LuaInstance () + : lua (true, UIConfiguration::instance().get_sandbox_all_lua_scripts ()) { lua.Print.connect (&_lua_print); init (); @@ -1196,7 +1199,6 @@ LuaInstance::~LuaInstance () void LuaInstance::init () { - lua.sandbox (false); lua.do_command ( "function ScriptManager ()" " local self = { scripts = {}, instances = {}, icons = {} }" @@ -1343,7 +1345,7 @@ LuaInstance::init () abort(); /*NOTREACHED*/ } - register_classes (L); + LuaInstance::register_classes (L, UIConfiguration::instance().get_sandbox_all_lua_scripts ()); register_hooks (L); luabridge::push (L, &PublicEditor::instance()); @@ -1527,8 +1529,8 @@ LuaInstance::pre_seed_script (std::string const& name, int& id) if (spi) { try { std::string script = Glib::file_get_contents (spi->path); - LuaState ls; - register_classes (ls.getState ()); + LuaState ls (true, true); + register_classes (ls.getState (), true); LuaScriptParamList lsp = LuaScriptParams::script_params (ls, spi->path, "action_params"); LuaScriptParamPtr lspp (new LuaScriptParam("x-script-origin", "", spi->path, false, true)); lsp.push_back (lspp); @@ -1595,8 +1597,8 @@ LuaInstance::interactive_add (Gtk::Window& parent, LuaScriptInfo::ScriptType typ return false; } - LuaState ls; - register_classes (ls.getState ()); + LuaState ls (true, true); + register_classes (ls.getState (), true); LuaScriptParamList lsp = LuaScriptParams::script_params (ls, spi->path, param_function); /* 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 */ ActionHook ah; try { - LuaState l; + LuaState l (true, true); l.Print.connect (&_lua_print); - l.sandbox (true); lua_State* L = l.getState(); register_hooks (L); l.do_command ("function ardour () end"); @@ -1972,6 +1973,7 @@ LuaCallback::LuaCallback (Session *s, const ActionHook& ah, const ARDOUR::LuaScriptParamList& args) : SessionHandlePtr (s) + , lua (true, UIConfiguration::instance().get_sandbox_all_lua_scripts ()) , _id ("0") , _name (name) , _signals (ah) @@ -2005,6 +2007,7 @@ LuaCallback::LuaCallback (Session *s, LuaCallback::LuaCallback (Session *s, XMLNode & node) : SessionHandlePtr (s) + , lua (true, UIConfiguration::instance().get_sandbox_all_lua_scripts ()) { XMLNode* child = NULL; if (node.name() != X_("LuaCallback") @@ -2088,7 +2091,6 @@ void LuaCallback::init (void) { lua.Print.connect (&_lua_print); - lua.sandbox (false); lua.do_command ( "function ScriptManager ()" @@ -2209,7 +2211,7 @@ LuaCallback::init (void) abort(); /*NOTREACHED*/ } - LuaInstance::register_classes (L); + LuaInstance::register_classes (L, UIConfiguration::instance().get_sandbox_all_lua_scripts ()); LuaInstance::register_hooks (L); luabridge::push (L, &PublicEditor::instance()); diff --git a/gtk2_ardour/luainstance.h b/gtk2_ardour/luainstance.h index ba16bf6591..15d9fb0590 100644 --- a/gtk2_ardour/luainstance.h +++ b/gtk2_ardour/luainstance.h @@ -112,7 +112,7 @@ public: static void destroy_instance(); ~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 bind_cairo (lua_State* L); static void bind_dialog (lua_State* L); diff --git a/gtk2_ardour/luawindow.cc b/gtk2_ardour/luawindow.cc index 6e19dbef3d..d3253365cc 100644 --- a/gtk2_ardour/luawindow.cc +++ b/gtk2_ardour/luawindow.cc @@ -197,12 +197,11 @@ void LuaWindow::reinit_lua () { ENSURE_GUI_THREAD (*this, &LuaWindow::session_going_away); 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->sandbox (false); lua_State* L = lua->getState(); - LuaInstance::register_classes (L); + LuaInstance::register_classes (L, UIConfiguration::instance().get_sandbox_all_lua_scripts ()); luabridge::push (L, &PublicEditor::instance()); lua_setglobal (L, "Editor"); } diff --git a/gtk2_ardour/processor_box.cc b/gtk2_ardour/processor_box.cc index 8534d41d91..d5eb8d2864 100644 --- a/gtk2_ardour/processor_box.cc +++ b/gtk2_ardour/processor_box.cc @@ -1869,6 +1869,7 @@ ProcessorEntry::PluginInlineDisplay::display_frame (cairo_t* cr, double w, doubl ProcessorEntry::LuaPluginDisplay::LuaPluginDisplay (ProcessorEntry& e, std::shared_ptr p, uint32_t max_height) : PluginInlineDisplay (e, p, max_height) , _luaproc (p) + , lua_gui (true, true) , _lua_render_inline (0) { p->setup_lua_inline_gui (&lua_gui); diff --git a/gtk2_ardour/session_dialog.cc b/gtk2_ardour/session_dialog.cc index a0d287d516..a28b93e990 100644 --- a/gtk2_ardour/session_dialog.cc +++ b/gtk2_ardour/session_dialog.cc @@ -189,8 +189,7 @@ SessionDialog::meta_master_bus_profile (std::string script_path) return UINT32_MAX; } - LuaState lua; - lua.sandbox (true); + LuaState lua (true, true); lua_State* L = lua.getState(); lua.do_command ( diff --git a/gtk2_ardour/ui_config_vars.h b/gtk2_ardour/ui_config_vars.h index 55d3b50925..63823526da 100644 --- a/gtk2_ardour/ui_config_vars.h +++ b/gtk2_ardour/ui_config_vars.h @@ -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 (int, max_note_height, "max-note-height", 20) 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 */ UI_CONFIG_VARIABLE (bool, show_on_cue_page, "show-on-cue-page", true)