From 906ff82cd82dd3f8946bfe43605d981d99391207 Mon Sep 17 00:00:00 2001 From: Reinder Feenstra Date: Sat, 13 Nov 2021 00:39:45 +0100 Subject: [PATCH] lua: made built-in globals read only --- server/src/lua/error.hpp | 4 ++- server/src/lua/sandbox.cpp | 69 +++++++++++++++++++++++++++++++++++--- server/src/lua/sandbox.hpp | 2 ++ 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/server/src/lua/error.hpp b/server/src/lua/error.hpp index 17c12e7c..bb9268c6 100644 --- a/server/src/lua/error.hpp +++ b/server/src/lua/error.hpp @@ -42,7 +42,9 @@ namespace Lua { [[noreturn]] inline void errorExpectedNArgumentsGotN(lua_State* L, int expected, int got) { luaL_error(L, "expected %d arguments, got %d", expected, got); abort(); } -[[noreturn]] inline void errorException(lua_State* L, const std::exception& e) { luaL_error(L, "exceptiop: %s", e.what()); abort(); } +[[noreturn]] inline void errorException(lua_State* L, const std::exception& e) { luaL_error(L, "exception: %s", e.what()); abort(); } + +[[noreturn]] inline void errorGlobalNIsReadOnly(lua_State* L, const char* name) { luaL_error(L, "global %s is readonly", name); abort(); } [[noreturn]] inline void errorInternal(lua_State* L) { luaL_error(L, "internal error"); abort(); } diff --git a/server/src/lua/sandbox.cpp b/server/src/lua/sandbox.cpp index 0ddd0170..1d1d6716 100644 --- a/server/src/lua/sandbox.cpp +++ b/server/src/lua/sandbox.cpp @@ -26,6 +26,7 @@ #include "method.hpp" #include "log.hpp" #include "class.hpp" +#include "to.hpp" #include #include #include @@ -37,12 +38,38 @@ #include "../set/worldstate.hpp" #define LUA_SANDBOX "_sandbox" +#define LUA_SANDBOX_GLOBALS "_sandbox_globals" #define ADD_GLOBAL_TO_SANDBOX(x) \ lua_pushliteral(L, x); \ lua_getglobal(L, x); \ lua_settable(L, -3); +constexpr std::array readOnlyGlobals = {{ + // Lua baselib: + "assert", + "type", + "pairs", + "ipairs", + "_G", + // Constants: + "VERSION", + "VERSION_MAJOR", + "VERSION_MINOR", + "VERSION_PATCH", + "CODENAME", + "LUA_VERSION", + // Objects: + "world", + "log", + // Functions: + "is_instance", + // Type info: + "class", + "enum", + "set", +}}; + namespace Lua { void Sandbox::close(lua_State* L) @@ -51,6 +78,29 @@ void Sandbox::close(lua_State* L) lua_close(L); } +int Sandbox::__index(lua_State* L) +{ + lua_getglobal(L, LUA_SANDBOX_GLOBALS); + lua_replace(L, 1); + + lua_rawget(L, 1); + + return 1; +} + +int Sandbox::__newindex(lua_State* L) +{ + if(std::find(readOnlyGlobals.begin(), readOnlyGlobals.end(), to(L, 2)) != readOnlyGlobals.end()) + errorGlobalNIsReadOnly(L, lua_tostring(L, 2)); + + lua_getglobal(L, LUA_SANDBOX_GLOBALS); + lua_replace(L, 1); + + lua_rawset(L, 1); + + return 0; +} + SandboxPtr Sandbox::create(Script& script) { lua_State* L = luaL_newstate(); @@ -74,6 +124,16 @@ SandboxPtr Sandbox::create(Script& script) // setup sandbox: lua_newtable(L); + luaL_newmetatable(L, LUA_SANDBOX); + lua_pushcfunction(L, __index); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, __newindex); + lua_setfield(L, -2, "__newindex"); + lua_setmetatable(L, -2); + lua_setglobal(L, LUA_SANDBOX); + + // setup globals: + lua_newtable(L); // add some Lua baselib functions to the sandbox: ADD_GLOBAL_TO_SANDBOX("assert") @@ -133,12 +193,11 @@ SandboxPtr Sandbox::create(Script& script) ReadOnlyTable::wrap(L, -1); lua_setfield(L, -2, "set"); - // let global _G point to itself: - lua_pushliteral(L, "_G"); - lua_pushvalue(L, -2); - lua_settable(L, -3); + // let global _G point to the sandbox: + lua_getglobal(L, LUA_SANDBOX); + lua_setfield(L, -2, "_G"); - lua_setglobal(L, LUA_SANDBOX); + lua_setglobal(L, LUA_SANDBOX_GLOBALS); return SandboxPtr(L, close); } diff --git a/server/src/lua/sandbox.hpp b/server/src/lua/sandbox.hpp index 4155222d..13e6ee56 100644 --- a/server/src/lua/sandbox.hpp +++ b/server/src/lua/sandbox.hpp @@ -36,6 +36,8 @@ class Sandbox { private: static void close(lua_State* L); + static int __index(lua_State* L); + static int __newindex(lua_State* L); public: class StateData