]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/script/cpp_api/s_security.cpp
Merge branch 'master' of https://github.com/minetest/minetest
[dragonfireclient.git] / src / script / cpp_api / s_security.cpp
index 6c50218d31ef71d3113e7ec80c3a505714f5dbc9..37c5b61dcf89a7841b35a1c817628a76c7a3cb57 100644 (file)
@@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "filesys.h"
 #include "porting.h"
 #include "server.h"
-#include "client.h"
+#include "client/client.h"
 #include "settings.h"
 
 #include <cerrno>
@@ -90,6 +90,7 @@ void ScriptApiSecurity::initializeSecurity()
                "math",
        };
        static const char *io_whitelist[] = {
+               "open",
                "close",
                "flush",
                "read",
@@ -113,7 +114,6 @@ void ScriptApiSecurity::initializeSecurity()
                "setupvalue",
                "setmetatable",
                "upvalueid",
-               "upvaluejoin",
                "sethook",
                "debug",
                "setlocal",
@@ -174,7 +174,7 @@ void ScriptApiSecurity::initializeSecurity()
        copy_safe(L, io_whitelist, sizeof(io_whitelist));
 
        // And replace unsafe ones
-       SECURE_API(io, open);
+       //SECURE_API(io, open);
        SECURE_API(io, input);
        SECURE_API(io, output);
        SECURE_API(io, lines);
@@ -244,6 +244,7 @@ void ScriptApiSecurity::initializeSecurityClient()
                "rawset",
                "select",
                "setfenv",
+               // getmetatable can be used to escape the sandbox
                "setmetatable",
                "tonumber",
                "tostring",
@@ -265,8 +266,8 @@ void ScriptApiSecurity::initializeSecurityClient()
        };
        static const char *debug_whitelist[] = {
                "getinfo",
+               "traceback"
        };
-
 #if USE_LUAJIT
        static const char *jit_whitelist[] = {
                "arch",
@@ -286,6 +287,10 @@ void ScriptApiSecurity::initializeSecurityClient()
        lua_State *L = getStack();
        int thread = getThread(L);
 
+       // Backup globals to the registry
+       lua_getglobal(L, "_G");
+       lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
+
        // create an empty environment
        createEmptyEnv(L);
 
@@ -302,8 +307,6 @@ void ScriptApiSecurity::initializeSecurityClient()
        SECURE_API(g, require);
        lua_pop(L, 2);
 
-
-
        // Copy safe OS functions
        lua_getglobal(L, "os");
        lua_newtable(L);
@@ -318,6 +321,7 @@ void ScriptApiSecurity::initializeSecurityClient()
        copy_safe(L, debug_whitelist, sizeof(debug_whitelist));
        lua_setfield(L, -3, "debug");
        lua_pop(L, 1);  // Pop old debug
+       
 
 #if USE_LUAJIT
        // Copy safe jit functions, if they exist
@@ -371,14 +375,16 @@ bool ScriptApiSecurity::isSecure(lua_State *L)
        return secure;
 }
 
-
-#define CHECK_FILE_ERR(ret, fp) \
-       if (ret) { \
-               lua_pushfstring(L, "%s: %s", path, strerror(errno)); \
-               if (fp) std::fclose(fp); \
-               return false; \
+bool ScriptApiSecurity::safeLoadString(lua_State *L, const std::string &code, const char *chunk_name)
+{
+       if (code.size() > 0 && code[0] == LUA_SIGNATURE[0]) {
+               lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
+               return false;
        }
-
+       if (luaL_loadbuffer(L, code.data(), code.size(), chunk_name))
+               return false;
+       return true;
+}
 
 bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char *display_name)
 {
@@ -395,78 +401,58 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char
                        lua_pushfstring(L, "%s: %s", path, strerror(errno));
                        return false;
                }
-               chunk_name = new char[strlen(display_name) + 2];
-               chunk_name[0] = '@';
-               chunk_name[1] = '\0';
-               strcat(chunk_name, display_name);
+               size_t len = strlen(display_name) + 2;
+               chunk_name = new char[len];
+               snprintf(chunk_name, len, "@%s", display_name);
        }
 
        size_t start = 0;
        int c = std::getc(fp);
        if (c == '#') {
                // Skip the first line
-               while ((c = std::getc(fp)) != EOF && c != '\n');
-               if (c == '\n') c = std::getc(fp);
+               while ((c = std::getc(fp)) != EOF && c != '\n') {}
+               if (c == '\n')
+                       std::getc(fp);
                start = std::ftell(fp);
        }
 
-       if (c == LUA_SIGNATURE[0]) {
-               lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
-               std::fclose(fp);
-               if (path) {
-                       delete [] chunk_name;
-               }
-               return false;
-       }
-
        // Read the file
        int ret = std::fseek(fp, 0, SEEK_END);
        if (ret) {
                lua_pushfstring(L, "%s: %s", path, strerror(errno));
-               std::fclose(fp);
                if (path) {
+                       std::fclose(fp);
                        delete [] chunk_name;
                }
                return false;
        }
 
        size_t size = std::ftell(fp) - start;
-       char *code = new char[size];
+       std::string code(size, '\0');
        ret = std::fseek(fp, start, SEEK_SET);
        if (ret) {
                lua_pushfstring(L, "%s: %s", path, strerror(errno));
-               std::fclose(fp);
-               delete [] code;
                if (path) {
+                       std::fclose(fp);
                        delete [] chunk_name;
                }
                return false;
        }
 
-       size_t num_read = std::fread(code, 1, size, fp);
-       if (path) {
+       size_t num_read = std::fread(&code[0], 1, size, fp);
+       if (path)
                std::fclose(fp);
-       }
        if (num_read != size) {
                lua_pushliteral(L, "Error reading file to load.");
-               delete [] code;
-               if (path) {
+               if (path)
                        delete [] chunk_name;
-               }
-               return false;
-       }
-
-       if (luaL_loadbuffer(L, code, size, chunk_name)) {
-               delete [] code;
                return false;
        }
 
-       delete [] code;
-
-       if (path) {
+       bool result = safeLoadString(L, code, chunk_name);
+       if (path)
                delete [] chunk_name;
-       }
-       return true;
+       return result;
 }
 
 
@@ -515,7 +501,12 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path,
 
        // Get server from registry
        lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI);
-       ScriptApiBase *script = (ScriptApiBase *) lua_touserdata(L, -1);
+       ScriptApiBase *script;
+#if INDIRECT_SCRIPTAPI_RIDX
+       script = (ScriptApiBase *) *(void**)(lua_touserdata(L, -1));
+#else
+       script = (ScriptApiBase *) lua_touserdata(L, -1);
+#endif
        lua_pop(L, 1);
        const IGameDef *gamedef = script->getGameDef();
        if (!gamedef)
@@ -524,7 +515,7 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path,
        // Get mod name
        lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
        if (lua_isstring(L, -1)) {
-               std::string mod_name = lua_tostring(L, -1);
+               std::string mod_name = readParam<std::string>(L, -1);
 
                // Builtin can access anything
                if (mod_name == BUILTIN_MOD_NAME) {
@@ -627,14 +618,9 @@ int ScriptApiSecurity::sl_g_load(lua_State *L)
                code += std::string(buf, len);
                lua_pop(L, 1); // Pop return value
        }
-       if (code[0] == LUA_SIGNATURE[0]) {
-               lua_pushnil(L);
-               lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
-               return 2;
-       }
-       if (luaL_loadbuffer(L, code.data(), code.size(), chunk_name)) {
+       if (!safeLoadString(L, code, chunk_name)) {
                lua_pushnil(L);
-               lua_insert(L, lua_gettop(L) - 1);
+               lua_insert(L, -2);
                return 2;
        }
        return 1;
@@ -645,19 +631,26 @@ int ScriptApiSecurity::sl_g_loadfile(lua_State *L)
 {
 #ifndef SERVER
        lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI);
+#if INDIRECT_SCRIPTAPI_RIDX
+       ScriptApiBase *script = (ScriptApiBase *) *(void**)(lua_touserdata(L, -1));
+#else
        ScriptApiBase *script = (ScriptApiBase *) lua_touserdata(L, -1);
+#endif
        lua_pop(L, 1);
 
+       // Client implementation
        if (script->getType() == ScriptingType::Client) {
-               std:: string display_path = lua_tostring(L, 1);
-               const std::string *path = script->getClient()->getModFile(display_path);
-               if (!path) {
-                       std::string error_msg = "Coudln't find script called:" + display_path;
+               std::string path = readParam<std::string>(L, 1);
+               const std::string *contents = script->getClient()->getModFile(path);
+               if (!contents) {
+                       std::string error_msg = "Coudln't find script called: " + path;
                        lua_pushnil(L);
                        lua_pushstring(L, error_msg.c_str());
                        return 2;
                }
-               if (!safeLoadFile(L, path->c_str(), display_path.c_str())) {
+
+               std::string chunk_name = "@" + path;
+               if (!safeLoadString(L, *contents, chunk_name.c_str())) {
                        lua_pushnil(L);
                        lua_insert(L, -2);
                        return 2;
@@ -665,6 +658,8 @@ int ScriptApiSecurity::sl_g_loadfile(lua_State *L)
                return 1;
        }
 #endif
+
+       // Server implementation
        const char *path = NULL;
        if (lua_isstring(L, 1)) {
                path = lua_tostring(L, 1);
@@ -693,15 +688,11 @@ int ScriptApiSecurity::sl_g_loadstring(lua_State *L)
 
        size_t size;
        const char *code = lua_tolstring(L, 1, &size);
+       std::string code_s(code, size);
 
-       if (size > 0 && code[0] == LUA_SIGNATURE[0]) {
-               lua_pushnil(L);
-               lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
-               return 2;
-       }
-       if (luaL_loadbuffer(L, code, size, chunk_name)) {
+       if (!safeLoadString(L, code_s, chunk_name)) {
                lua_pushnil(L);
-               lua_insert(L, lua_gettop(L) - 1);
+               lua_insert(L, -2);
                return 2;
        }
        return 1;