|
@@ -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)
|
|
|
{
|