summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin/client/register.lua5
-rw-r--r--builtin/common/strict.lua5
-rw-r--r--builtin/init.lua1
-rw-r--r--src/script/clientscripting.cpp2
-rw-r--r--src/script/cpp_api/s_security.cpp185
-rw-r--r--src/script/cpp_api/s_security.h2
6 files changed, 171 insertions, 29 deletions
diff --git a/builtin/client/register.lua b/builtin/client/register.lua
index 1e6ac4342..c932fb9f8 100644
--- a/builtin/client/register.lua
+++ b/builtin/client/register.lua
@@ -1,6 +1,9 @@
core.callback_origins = {}
+local getinfo = debug.getinfo
+debug.getinfo = nil
+
function core.run_callbacks(callbacks, mode, ...)
assert(type(callbacks) == "table")
local cb_len = #callbacks
@@ -47,7 +50,7 @@ local function make_registration()
t[#t + 1] = func
core.callback_origins[func] = {
mod = core.get_current_modname() or "??",
- name = debug.getinfo(1, "n").name or "??"
+ name = getinfo(1, "n").name or "??"
}
--local origin = core.callback_origins[func]
--print(origin.name .. ": " .. origin.mod .. " registering cbk " .. tostring(func))
diff --git a/builtin/common/strict.lua b/builtin/common/strict.lua
index 23ba3d727..ccde9676b 100644
--- a/builtin/common/strict.lua
+++ b/builtin/common/strict.lua
@@ -3,6 +3,7 @@
-- This ignores mod namespaces (variables with the same name as the current mod).
local WARN_INIT = false
+local getinfo = debug.getinfo
function core.global_exists(name)
if type(name) ~= "string" then
@@ -18,7 +19,7 @@ local declared = {}
local warned = {}
function meta:__newindex(name, value)
- local info = debug.getinfo(2, "Sl")
+ local info = getinfo(2, "Sl")
local desc = ("%s:%d"):format(info.short_src, info.currentline)
if not declared[name] then
local warn_key = ("%s\0%d\0%s"):format(info.source,
@@ -42,7 +43,7 @@ end
function meta:__index(name)
- local info = debug.getinfo(2, "Sl")
+ local info = getinfo(2, "Sl")
local warn_key = ("%s\0%d\0%s"):format(info.source, info.currentline, name)
if not declared[name] and not warned[warn_key] and info.what ~= "C" then
core.log("warning", ("Undeclared global variable %q accessed at %s:%s")
diff --git a/builtin/init.lua b/builtin/init.lua
index 590f7fa8c..c9fa70fc7 100644
--- a/builtin/init.lua
+++ b/builtin/init.lua
@@ -47,6 +47,7 @@ elseif INIT == "mainmenu" then
elseif INIT == "async" then
dofile(asyncpath .. "init.lua")
elseif INIT == "client" then
+ os.setlocale = nil
dofile(clientpath .. "init.lua")
else
error(("Unrecognized builtin initialization type %s!"):format(tostring(INIT)))
diff --git a/src/script/clientscripting.cpp b/src/script/clientscripting.cpp
index 370324433..390d21a3a 100644
--- a/src/script/clientscripting.cpp
+++ b/src/script/clientscripting.cpp
@@ -33,7 +33,7 @@ ClientScripting::ClientScripting(Client *client):
SCRIPTAPI_PRECHECKHEADER
// Security is mandatory client side
- initializeSecurity();
+ initializeSecurityClient();
lua_getglobal(L, "core");
int top = lua_gettop(L);
diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp
index f85cd0c9c..c6aad71b8 100644
--- a/src/script/cpp_api/s_security.cpp
+++ b/src/script/cpp_api/s_security.cpp
@@ -139,32 +139,8 @@ void ScriptApiSecurity::initializeSecurity()
lua_State *L = getStack();
- // Backup globals to the registry
- lua_getglobal(L, "_G");
- lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
-
- // Replace the global environment with an empty one
-#if LUA_VERSION_NUM <= 501
- int is_main = lua_pushthread(L); // Push the main thread
- FATAL_ERROR_IF(!is_main, "Security: ScriptApi's Lua state "
- "isn't the main Lua thread!");
-#endif
- lua_newtable(L); // Create new environment
- lua_pushvalue(L, -1);
- lua_setfield(L, -2, "_G"); // Set _G of new environment
-#if LUA_VERSION_NUM >= 502 // Lua >= 5.2
- // Set the global environment
- lua_rawseti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
-#else // Lua <= 5.1
- // Set the environment of the main thread
- FATAL_ERROR_IF(!lua_setfenv(L, -2), "Security: Unable to set "
- "environment of the main Lua thread!");
- lua_pop(L, 1); // Pop thread
-#endif
- // Get old globals
- lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
- int old_globals = lua_gettop(L);
+ int old_globals = backupGlobals(L);
// Copy safe base functions
@@ -223,7 +199,136 @@ void ScriptApiSecurity::initializeSecurity()
lua_setglobal(L, "package");
lua_pop(L, 1); // Pop old package
+#if USE_LUAJIT
+ // Copy safe jit functions, if they exist
+ lua_getfield(L, -1, "jit");
+ if (!lua_isnil(L, -1)) {
+ lua_newtable(L);
+ copy_safe(L, jit_whitelist, sizeof(jit_whitelist));
+ lua_setglobal(L, "jit");
+ }
+ lua_pop(L, 1); // Pop old jit
+#endif
+
+ lua_pop(L, 1); // Pop globals_backup
+}
+
+void ScriptApiSecurity::initializeSecurityClient()
+{
+ static const char *whitelist[] = {
+ "assert",
+ "core",
+ "collectgarbage",
+ "DIR_DELIM",
+ "error",
+ "getfenv",
+ "ipairs",
+ "next",
+ "pairs",
+ "pcall",
+ "print",
+ "rawequal",
+ "rawget",
+ "rawset",
+ "select",
+ "setfenv",
+ "setmetatable",
+ "tonumber",
+ "tostring",
+ "type",
+ "unpack",
+ "_VERSION",
+ "xpcall",
+ // Completely safe libraries
+ "coroutine",
+ "string",
+ "table",
+ "math",
+ };
+ static const char *io_whitelist[] = {
+ "close",
+ "flush",
+ "read",
+ "type",
+ "write",
+ };
+ static const char *os_whitelist[] = {
+ "clock",
+ "date",
+ "difftime",
+ "time",
+ "setlocale",
+ };
+ static const char *debug_whitelist[] = {
+ "getinfo",
+ };
+ static const char *jit_whitelist[] = {
+ "arch",
+ "flush",
+ "off",
+ "on",
+ "opt",
+ "os",
+ "status",
+ "version",
+ "version_num",
+ };
+
+ m_secure = true;
+
+ lua_State *L = getStack();
+
+
+ int old_globals = backupGlobals(L);
+
+
+ // Copy safe base functions
+ lua_getglobal(L, "_G");
+ copy_safe(L, whitelist, sizeof(whitelist));
+
+ // And replace unsafe ones
+ SECURE_API(g, dofile);
+ SECURE_API(g, loadstring);
+ SECURE_API(g, require);
+ lua_pop(L, 1);
+
+
+ // Copy safe IO functions
+ lua_getfield(L, old_globals, "io");
+ lua_newtable(L);
+ copy_safe(L, io_whitelist, sizeof(io_whitelist));
+
+ // And replace unsafe ones
+ SECURE_API(io, open);
+ SECURE_API(io, input);
+ SECURE_API(io, output);
+ SECURE_API(io, lines);
+
+ lua_setglobal(L, "io");
+ lua_pop(L, 1); // Pop old IO
+
+
+ // Copy safe OS functions
+ lua_getfield(L, old_globals, "os");
+ lua_newtable(L);
+ copy_safe(L, os_whitelist, sizeof(os_whitelist));
+ lua_setglobal(L, "os");
+ lua_pop(L, 1); // Pop old OS
+
+
+ // Copy safe debug functions
+ lua_getfield(L, old_globals, "debug");
+ lua_newtable(L);
+ copy_safe(L, debug_whitelist, sizeof(debug_whitelist));
+ lua_setglobal(L, "debug");
+ lua_pop(L, 1); // Pop old debug
+
+ // Remove all of package
+ lua_newtable(L);
+ lua_setglobal(L, "package");
+
+#if USE_LUAJIT
// Copy safe jit functions, if they exist
lua_getfield(L, -1, "jit");
if (!lua_isnil(L, -1)) {
@@ -232,10 +337,40 @@ void ScriptApiSecurity::initializeSecurity()
lua_setglobal(L, "jit");
}
lua_pop(L, 1); // Pop old jit
+#endif
lua_pop(L, 1); // Pop globals_backup
}
+int ScriptApiSecurity::backupGlobals(lua_State *L)
+{
+ // Backup globals to the registry
+ lua_getglobal(L, "_G");
+ lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
+
+ // Replace the global environment with an empty one
+#if LUA_VERSION_NUM <= 501
+ int is_main = lua_pushthread(L); // Push the main thread
+ FATAL_ERROR_IF(!is_main, "Security: ScriptApi's Lua state "
+ "isn't the main Lua thread!");
+#endif
+ lua_newtable(L); // Create new environment
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "_G"); // Set _G of new environment
+#if LUA_VERSION_NUM >= 502 // Lua >= 5.2
+ // Set the global environment
+ lua_rawseti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
+#else // Lua <= 5.1
+ // Set the environment of the main thread
+ FATAL_ERROR_IF(!lua_setfenv(L, -2), "Security: Unable to set "
+ "environment of the main Lua thread!");
+ lua_pop(L, 1); // Pop thread
+#endif
+
+ // Get old globals
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
+ return lua_gettop(L);
+}
bool ScriptApiSecurity::isSecure(lua_State *L)
{
diff --git a/src/script/cpp_api/s_security.h b/src/script/cpp_api/s_security.h
index 6876108e8..f0eef00bb 100644
--- a/src/script/cpp_api/s_security.h
+++ b/src/script/cpp_api/s_security.h
@@ -41,8 +41,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class ScriptApiSecurity : virtual public ScriptApiBase
{
public:
+ int backupGlobals(lua_State *L);
// Sets up security on the ScriptApi's Lua state
void initializeSecurity();
+ void initializeSecurityClient();
// Checks if the Lua state has been secured
static bool isSecure(lua_State *L);
// Loads a file as Lua code safely (doesn't allow bytecode).