+void ScriptApiSecurity::initializeSecurityClient()
+{
+ static const char *whitelist[] = {
+ "assert",
+ "core",
+ "collectgarbage",
+ "DIR_DELIM",
+ "error",
+ "getfenv",
+ "ipairs",
+ "next",
+ "pairs",
+ "pcall",
+ "print",
+ "rawequal",
+ "rawget",
+ "rawset",
+ "select",
+ "setfenv",
+ // getmetatable can be used to escape the sandbox
+ "setmetatable",
+ "tonumber",
+ "tostring",
+ "type",
+ "unpack",
+ "_VERSION",
+ "xpcall",
+ // Completely safe libraries
+ "coroutine",
+ "string",
+ "table",
+ "math",
+ };
+ static const char *os_whitelist[] = {
+ "clock",
+ "date",
+ "difftime",
+ "time"
+ };
+ static const char *debug_whitelist[] = {
+ "getinfo",
+ "traceback"
+ };
+
+#if USE_LUAJIT
+ static const char *jit_whitelist[] = {
+ "arch",
+ "flush",
+ "off",
+ "on",
+ "opt",
+ "os",
+ "status",
+ "version",
+ "version_num",
+ };
+#endif
+
+ m_secure = true;
+
+ lua_State *L = getStack();
+ int thread = getThread(L);
+
+ // create an empty environment
+ createEmptyEnv(L);
+
+ // Copy safe base functions
+ lua_getglobal(L, "_G");
+ lua_getfield(L, -2, "_G");
+ copy_safe(L, whitelist, sizeof(whitelist));
+
+ // And replace unsafe ones
+ SECURE_API(g, dofile);
+ SECURE_API(g, load);
+ SECURE_API(g, loadfile);
+ SECURE_API(g, loadstring);
+ SECURE_API(g, require);
+ lua_pop(L, 2);
+
+
+
+ // Copy safe OS functions
+ lua_getglobal(L, "os");
+ lua_newtable(L);
+ copy_safe(L, os_whitelist, sizeof(os_whitelist));
+ lua_setfield(L, -3, "os");
+ lua_pop(L, 1); // Pop old OS
+
+
+ // Copy safe debug functions
+ lua_getglobal(L, "debug");
+ lua_newtable(L);
+ 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
+ lua_getglobal(L, "jit");
+ lua_newtable(L);
+ copy_safe(L, jit_whitelist, sizeof(jit_whitelist));
+ lua_setfield(L, -3, "jit");
+ lua_pop(L, 1); // Pop old jit
+#endif
+
+ // Set the environment to the one we created earlier
+ setLuaEnv(L, thread);
+}
+
+int ScriptApiSecurity::getThread(lua_State *L)
+{
+#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!");
+ return lua_gettop(L);
+#endif
+ return 0;
+}
+
+void ScriptApiSecurity::createEmptyEnv(lua_State *L)
+{
+ lua_newtable(L); // Create new environment
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "_G"); // Create the _G loop
+}
+
+void ScriptApiSecurity::setLuaEnv(lua_State *L, int thread)
+{
+#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, thread), "Security: Unable to set "
+ "environment of the main Lua thread!");
+ lua_pop(L, 1); // Pop thread
+#endif
+}