// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details // This code is based on Lua 5.x implementation licensed under MIT License; see lua_LICENSE.txt for details #include "lualib.h" #include "lstate.h" #include LUAU_FASTFLAG(LuauIntegerLibrary) LUAU_FASTFLAG(DebugLuauUserDefinedClassesRuntime) LUAU_FASTFLAGVARIABLE(LuauSandboxFreezesVectorMetatable) static const luaL_Reg lualibs[] = { {"", luaopen_base}, {LUA_COLIBNAME, luaopen_coroutine}, {LUA_TABLIBNAME, luaopen_table}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_DBLIBNAME, luaopen_debug}, {LUA_UTF8LIBNAME, luaopen_utf8}, {LUA_BITLIBNAME, luaopen_bit32}, {LUA_BUFFERLIBNAME, luaopen_buffer}, {LUA_VECLIBNAME, luaopen_vector}, {LUA_INTLIBNAME, luaopen_integer}, {NULL, NULL}, }; static const luaL_Reg lualibs_NOINTEGER[] = { {"", luaopen_base}, {LUA_COLIBNAME, luaopen_coroutine}, {LUA_TABLIBNAME, luaopen_table}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_DBLIBNAME, luaopen_debug}, {LUA_UTF8LIBNAME, luaopen_utf8}, {LUA_BITLIBNAME, luaopen_bit32}, {LUA_BUFFERLIBNAME, luaopen_buffer}, {LUA_VECLIBNAME, luaopen_vector}, {NULL, NULL}, }; void luaL_openlibs(lua_State* L) { const luaL_Reg* lib; if (FFlag::LuauIntegerLibrary) lib = lualibs; else lib = lualibs_NOINTEGER; for (; lib->func; lib++) { lua_pushcfunction(L, lib->func, NULL); lua_pushstring(L, lib->name); lua_call(L, 1, 0); } if (FFlag::DebugLuauUserDefinedClassesRuntime) { lua_pushcfunction(L, luaopen_class, NULL); lua_pushstring(L, LUA_CLASSLIBNAME); lua_call(L, 1, 0); } } void luaL_sandbox(lua_State* L) { // set all libraries to read-only lua_pushnil(L); while (lua_next(L, LUA_GLOBALSINDEX) != 0) { if (lua_istable(L, -1)) lua_setreadonly(L, -1, true); lua_pop(L, 1); } // set all builtin metatables to read-only lua_pushliteral(L, ""); if (lua_getmetatable(L, -1)) { lua_setreadonly(L, -1, true); lua_pop(L, 2); } else { lua_pop(L, 1); } if (FFlag::LuauSandboxFreezesVectorMetatable) { #if LUA_VECTOR_SIZE == 4 lua_pushvector(L, 0.0f, 0.0f, 0.0f, 0.0f); #else lua_pushvector(L, 0.0f, 0.0f, 0.0f); #endif if (lua_getmetatable(L, -1)) { lua_setreadonly(L, -1, true); lua_pop(L, 2); } else { lua_pop(L, 1); } } // set globals to readonly and activate safeenv since the env is immutable lua_setreadonly(L, LUA_GLOBALSINDEX, true); lua_setsafeenv(L, LUA_GLOBALSINDEX, true); } void luaL_sandboxthread(lua_State* L) { // create new global table that proxies reads to original table lua_newtable(L); lua_newtable(L); lua_pushvalue(L, LUA_GLOBALSINDEX); lua_setfield(L, -2, "__index"); lua_setreadonly(L, -1, true); lua_setmetatable(L, -2); // we can set safeenv now although it's important to set it to false if code is loaded twice into the thread lua_replace(L, LUA_GLOBALSINDEX); lua_setsafeenv(L, LUA_GLOBALSINDEX, true); } static void* l_alloc(void* ud, void* ptr, size_t osize, size_t nsize) { (void)ud; (void)osize; if (nsize == 0) { free(ptr); return NULL; } else return realloc(ptr, nsize); } lua_State* luaL_newstate(void) { return lua_newstate(l_alloc, NULL); }