LCOV - code coverage report
Current view: top level - src/script/cpp_api - s_security.cpp (source / functions) Hit Total Coverage
Test: report Lines: 1 283 0.4 %
Date: 2015-07-11 18:23:49 Functions: 2 19 10.5 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
       4             : 
       5             : This program is free software; you can redistribute it and/or modify
       6             : it under the terms of the GNU Lesser General Public License as published by
       7             : the Free Software Foundation; either version 2.1 of the License, or
       8             : (at your option) any later version.
       9             : 
      10             : This program is distributed in the hope that it will be useful,
      11             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             : GNU Lesser General Public License for more details.
      14             : 
      15             : You should have received a copy of the GNU Lesser General Public License along
      16             : with this program; if not, write to the Free Software Foundation, Inc.,
      17             : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             : */
      19             : 
      20             : #include "cpp_api/s_security.h"
      21             : 
      22             : #include "filesys.h"
      23             : #include "porting.h"
      24             : #include "server.h"
      25             : #include "settings.h"
      26             : 
      27             : #include <cerrno>
      28             : #include <string>
      29             : #include <iostream>
      30             : 
      31             : 
      32             : #define SECURE_API(lib, name) \
      33             :         lua_pushcfunction(L, sl_##lib##_##name); \
      34             :         lua_setfield(L, -2, #name);
      35             : 
      36             : 
      37           0 : static inline void copy_safe(lua_State *L, const char *list[], unsigned len, int from=-2, int to=-1)
      38             : {
      39           0 :         if (from < 0) from = lua_gettop(L) + from + 1;
      40           0 :         if (to   < 0) to   = lua_gettop(L) + to   + 1;
      41           0 :         for (unsigned i = 0; i < (len / sizeof(list[0])); i++) {
      42           0 :                 lua_getfield(L, from, list[i]);
      43           0 :                 lua_setfield(L, to,   list[i]);
      44             :         }
      45           0 : }
      46             : 
      47             : // Pushes the original version of a library function on the stack, from the old version
      48           0 : static inline void push_original(lua_State *L, const char *lib, const char *func)
      49             : {
      50           0 :         lua_getfield(L, LUA_REGISTRYINDEX, "globals_backup");
      51           0 :         lua_getfield(L, -1, lib);
      52           0 :         lua_remove(L, -2);  // Remove globals_backup
      53           0 :         lua_getfield(L, -1, func);
      54           0 :         lua_remove(L, -2);  // Remove lib
      55           0 : }
      56             : 
      57             : 
      58           0 : void ScriptApiSecurity::initializeSecurity()
      59             : {
      60             :         static const char *whitelist[] = {
      61             :                 "assert",
      62             :                 "core",
      63             :                 "collectgarbage",
      64             :                 "DIR_DELIM",
      65             :                 "error",
      66             :                 "getfenv",
      67             :                 "getmetatable",
      68             :                 "ipairs",
      69             :                 "next",
      70             :                 "pairs",
      71             :                 "pcall",
      72             :                 "print",
      73             :                 "rawequal",
      74             :                 "rawget",
      75             :                 "rawset",
      76             :                 "select",
      77             :                 "setfenv",
      78             :                 "setmetatable",
      79             :                 "tonumber",
      80             :                 "tostring",
      81             :                 "type",
      82             :                 "unpack",
      83             :                 "_VERSION",
      84             :                 "xpcall",
      85             :                 // Completely safe libraries
      86             :                 "coroutine",
      87             :                 "string",
      88             :                 "table",
      89             :                 "math",
      90             :         };
      91             :         static const char *io_whitelist[] = {
      92             :                 "close",
      93             :                 "flush",
      94             :                 "read",
      95             :                 "type",
      96             :                 "write",
      97             :         };
      98             :         static const char *os_whitelist[] = {
      99             :                 "clock",
     100             :                 "date",
     101             :                 "difftime",
     102             :                 "exit",
     103             :                 "getenv",
     104             :                 "setlocale",
     105             :                 "time",
     106             :                 "tmpname",
     107             :         };
     108             :         static const char *debug_whitelist[] = {
     109             :                 "gethook",
     110             :                 "traceback",
     111             :                 "getinfo",
     112             :                 "getmetatable",
     113             :                 "setupvalue",
     114             :                 "setmetatable",
     115             :                 "upvalueid",
     116             :                 "upvaluejoin",
     117             :                 "sethook",
     118             :                 "debug",
     119             :                 "getupvalue",
     120             :                 "setlocal",
     121             :         };
     122             :         static const char *package_whitelist[] = {
     123             :                 "config",
     124             :                 "cpath",
     125             :                 "path",
     126             :                 "searchpath",
     127             :         };
     128             :         static const char *jit_whitelist[] = {
     129             :                 "arch",
     130             :                 "flush",
     131             :                 "off",
     132             :                 "on",
     133             :                 "opt",
     134             :                 "os",
     135             :                 "status",
     136             :                 "version",
     137             :                 "version_num",
     138             :         };
     139             : 
     140           0 :         m_secure = true;
     141             : 
     142           0 :         lua_State *L = getStack();
     143             : 
     144             :         // Backup globals to the registry
     145           0 :         lua_getglobal(L, "_G");
     146           0 :         lua_setfield(L, LUA_REGISTRYINDEX, "globals_backup");
     147             : 
     148             :         // Replace the global environment with an empty one
     149             : #if LUA_VERSION_NUM <= 501
     150           0 :         int is_main = lua_pushthread(L);  // Push the main thread
     151           0 :         FATAL_ERROR_IF(!is_main, "Security: ScriptApi's Lua state "
     152           0 :                         "isn't the main Lua thread!");
     153             : #endif
     154           0 :         lua_newtable(L);  // Create new environment
     155           0 :         lua_pushvalue(L, -1);
     156           0 :         lua_setfield(L, -2, "_G");  // Set _G of new environment
     157             : #if LUA_VERSION_NUM >= 502  // Lua >= 5.2
     158             :         // Set the global environment
     159             :         lua_rawseti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
     160             : #else  // Lua <= 5.1
     161             :         // Set the environment of the main thread
     162           0 :         FATAL_ERROR_IF(!lua_setfenv(L, -2), "Security: Unable to set "
     163           0 :                         "environment of the main Lua thread!");
     164           0 :         lua_pop(L, 1);  // Pop thread
     165             : #endif
     166             : 
     167             :         // Get old globals
     168           0 :         lua_getfield(L, LUA_REGISTRYINDEX, "globals_backup");
     169           0 :         int old_globals = lua_gettop(L);
     170             : 
     171             : 
     172             :         // Copy safe base functions
     173           0 :         lua_getglobal(L, "_G");
     174           0 :         copy_safe(L, whitelist, sizeof(whitelist));
     175             : 
     176             :         // And replace unsafe ones
     177           0 :         SECURE_API(g, dofile);
     178           0 :         SECURE_API(g, load);
     179           0 :         SECURE_API(g, loadfile);
     180           0 :         SECURE_API(g, loadstring);
     181           0 :         SECURE_API(g, require);
     182           0 :         lua_pop(L, 1);
     183             : 
     184             : 
     185             :         // Copy safe IO functions
     186           0 :         lua_getfield(L, old_globals, "io");
     187           0 :         lua_newtable(L);
     188           0 :         copy_safe(L, io_whitelist, sizeof(io_whitelist));
     189             : 
     190             :         // And replace unsafe ones
     191           0 :         SECURE_API(io, open);
     192           0 :         SECURE_API(io, input);
     193           0 :         SECURE_API(io, output);
     194           0 :         SECURE_API(io, lines);
     195             : 
     196           0 :         lua_setglobal(L, "io");
     197           0 :         lua_pop(L, 1);  // Pop old IO
     198             : 
     199             : 
     200             :         // Copy safe OS functions
     201           0 :         lua_getfield(L, old_globals, "os");
     202           0 :         lua_newtable(L);
     203           0 :         copy_safe(L, os_whitelist, sizeof(os_whitelist));
     204             : 
     205             :         // And replace unsafe ones
     206           0 :         SECURE_API(os, remove);
     207           0 :         SECURE_API(os, rename);
     208             : 
     209           0 :         lua_setglobal(L, "os");
     210           0 :         lua_pop(L, 1);  // Pop old OS
     211             : 
     212             : 
     213             :         // Copy safe debug functions
     214           0 :         lua_getfield(L, old_globals, "debug");
     215           0 :         lua_newtable(L);
     216           0 :         copy_safe(L, debug_whitelist, sizeof(debug_whitelist));
     217           0 :         lua_setglobal(L, "debug");
     218           0 :         lua_pop(L, 1);  // Pop old debug
     219             : 
     220             : 
     221             :         // Copy safe package fields
     222           0 :         lua_getfield(L, old_globals, "package");
     223           0 :         lua_newtable(L);
     224           0 :         copy_safe(L, package_whitelist, sizeof(package_whitelist));
     225           0 :         lua_setglobal(L, "package");
     226           0 :         lua_pop(L, 1);  // Pop old package
     227             : 
     228             : 
     229             :         // Copy safe jit functions, if they exist
     230           0 :         lua_getfield(L, -1, "jit");
     231           0 :         if (!lua_isnil(L, -1)) {
     232           0 :                 lua_newtable(L);
     233           0 :                 copy_safe(L, jit_whitelist, sizeof(jit_whitelist));
     234           0 :                 lua_setglobal(L, "jit");
     235             :         }
     236           0 :         lua_pop(L, 1);  // Pop old jit
     237             : 
     238           0 :         lua_pop(L, 1); // Pop globals_backup
     239           0 : }
     240             : 
     241             : 
     242           0 : bool ScriptApiSecurity::isSecure(lua_State *L)
     243             : {
     244           0 :         lua_getfield(L, LUA_REGISTRYINDEX, "globals_backup");
     245           0 :         bool secure = !lua_isnil(L, -1);
     246           0 :         lua_pop(L, 1);
     247           0 :         return secure;
     248             : }
     249             : 
     250             : 
     251             : #define CHECK_FILE_ERR(ret, fp) \
     252             :         if (ret) { \
     253             :                 if (fp) std::fclose(fp); \
     254             :                 lua_pushfstring(L, "%s: %s", path, strerror(errno)); \
     255             :                 return false; \
     256             :         }
     257             : 
     258             : 
     259           0 : bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path)
     260             : {
     261             :         FILE *fp;
     262             :         char *chunk_name;
     263           0 :         if (path == NULL) {
     264           0 :                 fp = stdin;
     265           0 :                 chunk_name = const_cast<char *>("=stdin");
     266             :         } else {
     267           0 :                 fp = fopen(path, "rb");
     268           0 :                 if (!fp) {
     269           0 :                         lua_pushfstring(L, "%s: %s", path, strerror(errno));
     270           0 :                         return false;
     271             :                 }
     272           0 :                 chunk_name = new char[strlen(path) + 2];
     273           0 :                 chunk_name[0] = '@';
     274           0 :                 chunk_name[1] = '\0';
     275           0 :                 strcat(chunk_name, path);
     276             :         }
     277             : 
     278           0 :         size_t start = 0;
     279           0 :         int c = std::getc(fp);
     280           0 :         if (c == '#') {
     281             :                 // Skip the first line
     282           0 :                 while ((c = std::getc(fp)) != EOF && c != '\n');
     283           0 :                 if (c == '\n') c = std::getc(fp);
     284           0 :                 start = std::ftell(fp);
     285             :         }
     286             : 
     287           0 :         if (c == LUA_SIGNATURE[0]) {
     288           0 :                 lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
     289           0 :                 return false;
     290             :         }
     291             : 
     292             :         // Read the file
     293           0 :         int ret = std::fseek(fp, 0, SEEK_END);
     294           0 :         CHECK_FILE_ERR(ret, fp);
     295           0 :         if (ret) {
     296           0 :                 std::fclose(fp);
     297           0 :                 lua_pushfstring(L, "%s: %s", path, strerror(errno));
     298           0 :                 return false;
     299             :         }
     300           0 :         size_t size = std::ftell(fp) - start;
     301           0 :         char *code = new char[size];
     302           0 :         ret = std::fseek(fp, start, SEEK_SET);
     303           0 :         CHECK_FILE_ERR(ret, fp);
     304           0 :         if (ret) {
     305           0 :                 std::fclose(fp);
     306           0 :                 lua_pushfstring(L, "%s: %s", path, strerror(errno));
     307           0 :                 return false;
     308             :         }
     309           0 :         size_t num_read = std::fread(code, 1, size, fp);
     310           0 :         if (path) {
     311           0 :                 std::fclose(fp);
     312             :         }
     313           0 :         if (num_read != size) {
     314           0 :                 lua_pushliteral(L, "Error reading file to load.");
     315           0 :                 return false;
     316             :         }
     317             : 
     318           0 :         if (luaL_loadbuffer(L, code, size, chunk_name)) {
     319           0 :                 return false;
     320             :         }
     321             : 
     322           0 :         if (path) {
     323           0 :                 delete [] chunk_name;
     324             :         }
     325           0 :         return true;
     326             : }
     327             : 
     328             : 
     329           0 : bool ScriptApiSecurity::checkPath(lua_State *L, const char *path)
     330             : {
     331           0 :         std::string str;  // Transient
     332             : 
     333           0 :         std::string norel_path = fs::RemoveRelativePathComponents(path);
     334           0 :         std::string abs_path = fs::AbsolutePath(norel_path);
     335             : 
     336           0 :         if (!abs_path.empty()) {
     337             :                 // Don't allow accessing the settings file
     338           0 :                 str = fs::AbsolutePath(g_settings_path);
     339           0 :                 if (str == abs_path) return false;
     340             :         }
     341             : 
     342             :         // If we couldn't find the absolute path (path doesn't exist) then
     343             :         // try removing the last components until it works (to allow
     344             :         // non-existent files/folders for mkdir).
     345           0 :         std::string cur_path = norel_path;
     346           0 :         std::string removed;
     347           0 :         while (abs_path.empty() && !cur_path.empty()) {
     348           0 :                 std::string tmp_rmed;
     349           0 :                 cur_path = fs::RemoveLastPathComponent(cur_path, &tmp_rmed);
     350           0 :                 removed = tmp_rmed + (removed.empty() ? "" : DIR_DELIM + removed);
     351           0 :                 abs_path = fs::AbsolutePath(cur_path);
     352             :         }
     353           0 :         if (abs_path.empty()) return false;
     354             :         // Add the removed parts back so that you can't, eg, create a
     355             :         // directory in worldmods if worldmods doesn't exist.
     356           0 :         if (!removed.empty()) abs_path += DIR_DELIM + removed;
     357             : 
     358             :         // Get server from registry
     359           0 :         lua_getfield(L, LUA_REGISTRYINDEX, "scriptapi");
     360           0 :         ScriptApiBase *script = (ScriptApiBase *) lua_touserdata(L, -1);
     361           0 :         lua_pop(L, 1);
     362           0 :         const Server *server = script->getServer();
     363             : 
     364           0 :         if (!server) return false;
     365             : 
     366             :         // Get mod name
     367           0 :         lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD);
     368           0 :         if (lua_isstring(L, -1)) {
     369           0 :                 std::string mod_name = lua_tostring(L, -1);
     370             : 
     371             :                 // Builtin can access anything
     372           0 :                 if (mod_name == BUILTIN_MOD_NAME) {
     373           0 :                         return true;
     374             :                 }
     375             : 
     376             :                 // Allow paths in mod path
     377           0 :                 const ModSpec *mod = server->getModSpec(mod_name);
     378           0 :                 if (mod) {
     379           0 :                         str = fs::AbsolutePath(mod->path);
     380           0 :                         if (!str.empty() && fs::PathStartsWith(abs_path, str)) {
     381           0 :                                 return true;
     382             :                         }
     383             :                 }
     384             :         }
     385           0 :         lua_pop(L, 1);  // Pop mod name
     386             : 
     387           0 :         str = fs::AbsolutePath(server->getWorldPath());
     388           0 :         if (str.empty()) return false;
     389             :         // Don't allow access to world mods.  We add to the absolute path
     390             :         // of the world instead of getting the absolute paths directly
     391             :         // because that won't work if they don't exist.
     392           0 :         if (fs::PathStartsWith(abs_path, str + DIR_DELIM + "worldmods") ||
     393           0 :                         fs::PathStartsWith(abs_path, str + DIR_DELIM + "game")) {
     394           0 :                 return false;
     395             :         }
     396             :         // Allow all other paths in world path
     397           0 :         if (fs::PathStartsWith(abs_path, str)) {
     398           0 :                 return true;
     399             :         }
     400             : 
     401             :         // Default to disallowing
     402           0 :         return false;
     403             : }
     404             : 
     405             : 
     406           0 : int ScriptApiSecurity::sl_g_dofile(lua_State *L)
     407             : {
     408           0 :         int nret = sl_g_loadfile(L);
     409           0 :         if (nret != 1) {
     410           0 :                 lua_error(L);
     411             :                 // code after this function isn't executed
     412             :         }
     413           0 :         int top_precall = lua_gettop(L);
     414           0 :         lua_call(L, 0, LUA_MULTRET);
     415             :         // Return number of arguments returned by the function,
     416             :         // adjusting for the function being poped.
     417           0 :         return lua_gettop(L) - (top_precall - 1);
     418             : }
     419             : 
     420             : 
     421           0 : int ScriptApiSecurity::sl_g_load(lua_State *L)
     422             : {
     423             :         size_t len;
     424             :         const char *buf;
     425           0 :         std::string code;
     426           0 :         const char *chunk_name = "=(load)";
     427             : 
     428           0 :         luaL_checktype(L, 1, LUA_TFUNCTION);
     429           0 :         if (!lua_isnone(L, 2)) {
     430           0 :                 luaL_checktype(L, 2, LUA_TSTRING);
     431           0 :                 chunk_name = lua_tostring(L, 2);
     432             :         }
     433             : 
     434           0 :         while (true) {
     435           0 :                 lua_pushvalue(L, 1);
     436           0 :                 lua_call(L, 0, 1);
     437           0 :                 int t = lua_type(L, -1);
     438           0 :                 if (t == LUA_TNIL) {
     439           0 :                         break;
     440           0 :                 } else if (t != LUA_TSTRING) {
     441           0 :                         lua_pushnil(L);
     442           0 :                         lua_pushliteral(L, "Loader didn't return a string");
     443           0 :                         return 2;
     444             :                 }
     445           0 :                 buf = lua_tolstring(L, -1, &len);
     446           0 :                 code += std::string(buf, len);
     447           0 :                 lua_pop(L, 1); // Pop return value
     448             :         }
     449           0 :         if (code[0] == LUA_SIGNATURE[0]) {
     450           0 :                 lua_pushnil(L);
     451           0 :                 lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
     452           0 :                 return 2;
     453             :         }
     454           0 :         if (luaL_loadbuffer(L, code.data(), code.size(), chunk_name)) {
     455           0 :                 lua_pushnil(L);
     456           0 :                 lua_insert(L, lua_gettop(L) - 1);
     457           0 :                 return 2;
     458             :         }
     459           0 :         return 1;
     460             : }
     461             : 
     462             : 
     463           0 : int ScriptApiSecurity::sl_g_loadfile(lua_State *L)
     464             : {
     465           0 :         const char *path = NULL;
     466             : 
     467           0 :         if (lua_isstring(L, 1)) {
     468           0 :                 path = lua_tostring(L, 1);
     469           0 :                 CHECK_SECURE_PATH(L, path);
     470             :         }
     471             : 
     472           0 :         if (!safeLoadFile(L, path)) {
     473           0 :                 lua_pushnil(L);
     474           0 :                 lua_insert(L, -2);
     475           0 :                 return 2;
     476             :         }
     477             : 
     478           0 :         return 1;
     479             : }
     480             : 
     481             : 
     482           0 : int ScriptApiSecurity::sl_g_loadstring(lua_State *L)
     483             : {
     484           0 :         const char *chunk_name = "=(load)";
     485             : 
     486           0 :         luaL_checktype(L, 1, LUA_TSTRING);
     487           0 :         if (!lua_isnone(L, 2)) {
     488           0 :                 luaL_checktype(L, 2, LUA_TSTRING);
     489           0 :                 chunk_name = lua_tostring(L, 2);
     490             :         }
     491             : 
     492             :         size_t size;
     493           0 :         const char *code = lua_tolstring(L, 1, &size);
     494             : 
     495           0 :         if (size > 0 && code[0] == LUA_SIGNATURE[0]) {
     496           0 :                 lua_pushnil(L);
     497           0 :                 lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
     498           0 :                 return 2;
     499             :         }
     500           0 :         if (luaL_loadbuffer(L, code, size, chunk_name)) {
     501           0 :                 lua_pushnil(L);
     502           0 :                 lua_insert(L, lua_gettop(L) - 1);
     503           0 :                 return 2;
     504             :         }
     505           0 :         return 1;
     506             : }
     507             : 
     508             : 
     509           0 : int ScriptApiSecurity::sl_g_require(lua_State *L)
     510             : {
     511           0 :         lua_pushliteral(L, "require() is disabled when mod security is on.");
     512           0 :         return lua_error(L);
     513             : }
     514             : 
     515             : 
     516           0 : int ScriptApiSecurity::sl_io_open(lua_State *L)
     517             : {
     518           0 :         luaL_checktype(L, 1, LUA_TSTRING);
     519           0 :         const char *path = lua_tostring(L, 1);
     520           0 :         CHECK_SECURE_PATH(L, path);
     521             : 
     522           0 :         push_original(L, "io", "open");
     523           0 :         lua_pushvalue(L, 1);
     524           0 :         lua_pushvalue(L, 2);
     525           0 :         lua_call(L, 2, 2);
     526           0 :         return 2;
     527             : }
     528             : 
     529             : 
     530           0 : int ScriptApiSecurity::sl_io_input(lua_State *L)
     531             : {
     532           0 :         if (lua_isstring(L, 1)) {
     533           0 :                 const char *path = lua_tostring(L, 1);
     534           0 :                 CHECK_SECURE_PATH(L, path);
     535             :         }
     536             : 
     537           0 :         push_original(L, "io", "input");
     538           0 :         lua_pushvalue(L, 1);
     539           0 :         lua_call(L, 1, 1);
     540           0 :         return 1;
     541             : }
     542             : 
     543             : 
     544           0 : int ScriptApiSecurity::sl_io_output(lua_State *L)
     545             : {
     546           0 :         if (lua_isstring(L, 1)) {
     547           0 :                 const char *path = lua_tostring(L, 1);
     548           0 :                 CHECK_SECURE_PATH(L, path);
     549             :         }
     550             : 
     551           0 :         push_original(L, "io", "output");
     552           0 :         lua_pushvalue(L, 1);
     553           0 :         lua_call(L, 1, 1);
     554           0 :         return 1;
     555             : }
     556             : 
     557             : 
     558           0 : int ScriptApiSecurity::sl_io_lines(lua_State *L)
     559             : {
     560           0 :         if (lua_isstring(L, 1)) {
     561           0 :                 const char *path = lua_tostring(L, 1);
     562           0 :                 CHECK_SECURE_PATH(L, path);
     563             :         }
     564             : 
     565           0 :         push_original(L, "io", "lines");
     566           0 :         lua_pushvalue(L, 1);
     567           0 :         int top_precall = lua_gettop(L);
     568           0 :         lua_call(L, 1, LUA_MULTRET);
     569             :         // Return number of arguments returned by the function,
     570             :         // adjusting for the function being poped.
     571           0 :         return lua_gettop(L) - (top_precall - 1);
     572             : }
     573             : 
     574             : 
     575           0 : int ScriptApiSecurity::sl_os_rename(lua_State *L)
     576             : {
     577           0 :         luaL_checktype(L, 1, LUA_TSTRING);
     578           0 :         const char *path1 = lua_tostring(L, 1);
     579           0 :         CHECK_SECURE_PATH(L, path1);
     580             : 
     581           0 :         luaL_checktype(L, 2, LUA_TSTRING);
     582           0 :         const char *path2 = lua_tostring(L, 2);
     583           0 :         CHECK_SECURE_PATH(L, path2);
     584             : 
     585           0 :         push_original(L, "os", "rename");
     586           0 :         lua_pushvalue(L, 1);
     587           0 :         lua_pushvalue(L, 2);
     588           0 :         lua_call(L, 2, 2);
     589           0 :         return 2;
     590             : }
     591             : 
     592             : 
     593           0 : int ScriptApiSecurity::sl_os_remove(lua_State *L)
     594             : {
     595           0 :         luaL_checktype(L, 1, LUA_TSTRING);
     596           0 :         const char *path = lua_tostring(L, 1);
     597           0 :         CHECK_SECURE_PATH(L, path);
     598             : 
     599           0 :         push_original(L, "os", "remove");
     600           0 :         lua_pushvalue(L, 1);
     601           0 :         lua_call(L, 1, 2);
     602           0 :         return 2;
     603           3 : }
     604             : 

Generated by: LCOV version 1.11