From d9b121948faf8cb04d34a3d360ff7e5d59109693 Mon Sep 17 00:00:00 2001 From: Reinder Feenstra Date: Thu, 22 Apr 2021 23:28:41 +0200 Subject: [PATCH] Lua: fix: ReadOnlyTable, existing keys could be written --- server/src/lua/console.cpp | 2 +- server/src/lua/enum.hpp | 2 +- server/src/lua/readonlytable.hpp | 48 +++++++++++++++++--------------- server/src/lua/sandbox.cpp | 4 +-- server/src/lua/set.hpp | 2 +- server/test/lua/enum.cpp | 1 - server/test/lua/set.cpp | 1 - 7 files changed, 31 insertions(+), 29 deletions(-) diff --git a/server/src/lua/console.cpp b/server/src/lua/console.cpp index be85b1fd..4997cfe1 100644 --- a/server/src/lua/console.cpp +++ b/server/src/lua/console.cpp @@ -54,7 +54,7 @@ void Console::push(lua_State* L) lua_pushcfunction(L, fatal); lua_setfield(L, -2, "fatal"); - ReadOnlyTable::setMetatable(L, -1); + ReadOnlyTable::wrap(L, -1); } void Console::log(lua_State* L, ::Console::Level level, const std::string& message) diff --git a/server/src/lua/enum.hpp b/server/src/lua/enum.hpp index ce6a7d51..8116a88f 100644 --- a/server/src/lua/enum.hpp +++ b/server/src/lua/enum.hpp @@ -98,7 +98,7 @@ struct Enum push(L, it.first); lua_setfield(L, -2, toUpper(it.second).c_str()); } - ReadOnlyTable::setMetatable(L, -1); + ReadOnlyTable::wrap(L, -1); lua_setfield(L, -2, EnumName::value); } }; diff --git a/server/src/lua/readonlytable.hpp b/server/src/lua/readonlytable.hpp index 09cece05..27422051 100644 --- a/server/src/lua/readonlytable.hpp +++ b/server/src/lua/readonlytable.hpp @@ -3,7 +3,7 @@ * * This file is part of the traintastic source code. * - * Copyright (C) 2019-2020 Reinder Feenstra + * Copyright (C) 2019-2021 Reinder Feenstra * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -29,29 +29,33 @@ namespace Lua { -struct ReadOnlyTable +class ReadOnlyTable { - static constexpr const char* metatableName = "read_only_table"; + private: + static int __newindex(lua_State* L) + { + errorTableIsReadOnly(L); + } - static void setMetatable(lua_State* L, int index) - { - luaL_getmetatable(L, metatableName); - assert(lua_istable(L, -1)); // is type registered? - lua_setmetatable(L, index < 0 ? index - 1 : index); - } - - static int __newindex(lua_State* L) - { - errorTableIsReadOnly(L); - } - - static void registerType(lua_State* L) - { - luaL_newmetatable(L, metatableName); - lua_pushcfunction(L, __newindex); - lua_setfield(L, -2, "__newindex"); - lua_pop(L, 1); - } + public: + static void wrap(lua_State* L, int index) + { + assert(lua_istable(L, index)); + lua_newtable(L); // create wrapper table + lua_newtable(L); // metatable for wrapper table + if(index < 0) + index -= 2; // correct index if relative + lua_pushvalue(L, index); // copy source table (ref) + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, __newindex); + lua_setfield(L, -2, "__newindex"); + lua_pushboolean(L, 0); + lua_setfield(L, -2, "__metatable"); + lua_setmetatable(L, -2); // set metatable @ wrapper table + if(index < 0) + index++; // correct index if relative + lua_replace(L, index); // replace source table by wrapper table + } }; } diff --git a/server/src/lua/sandbox.cpp b/server/src/lua/sandbox.cpp index 073cdb5a..49cf0111 100644 --- a/server/src/lua/sandbox.cpp +++ b/server/src/lua/sandbox.cpp @@ -98,13 +98,13 @@ SandboxPtr Sandbox::create(Script& script) Enum::registerValues(L); Enum::registerValues(L); Enum::registerValues(L); - ReadOnlyTable::setMetatable(L, -1); + ReadOnlyTable::wrap(L, -1); lua_setfield(L, -2, "enum"); // add set values: lua_newtable(L); Set::registerValues(L); - ReadOnlyTable::setMetatable(L, -1); + ReadOnlyTable::wrap(L, -1); lua_setfield(L, -2, "set"); // let global _G point to itself: diff --git a/server/src/lua/set.hpp b/server/src/lua/set.hpp index b133f6eb..7c49b42a 100644 --- a/server/src/lua/set.hpp +++ b/server/src/lua/set.hpp @@ -174,7 +174,7 @@ struct Set push(L, it.first); lua_setfield(L, -2, it.second); } - ReadOnlyTable::setMetatable(L, -1); + ReadOnlyTable::wrap(L, -1); lua_setfield(L, -2, set_name_v); } }; diff --git a/server/test/lua/enum.cpp b/server/test/lua/enum.cpp index 12b296f7..f18062cb 100644 --- a/server/test/lua/enum.cpp +++ b/server/test/lua/enum.cpp @@ -37,7 +37,6 @@ static lua_State* createState() { lua_State* L = newStateWithProtect(); - Lua::ReadOnlyTable::registerType(L); Lua::Enum::registerType(L); lua_createtable(L, 0, 1); diff --git a/server/test/lua/set.cpp b/server/test/lua/set.cpp index a25b9cde..9b264f2c 100644 --- a/server/test/lua/set.cpp +++ b/server/test/lua/set.cpp @@ -35,7 +35,6 @@ static lua_State* createState() { lua_State* L = newStateWithProtect(); - Lua::ReadOnlyTable::registerType(L); Lua::Set::registerType(L); lua_createtable(L, 0, 1);