Isolate library tables between sandbox and insecure env

This commit is contained in:
sfan5 2021-03-28 22:53:48 +02:00
parent 52c0384bd1
commit 623f0a8613
1 changed files with 43 additions and 1 deletions

View File

@ -45,6 +45,21 @@ static inline void copy_safe(lua_State *L, const char *list[], unsigned len, int
}
}
static void shallow_copy_table(lua_State *L, int from=-2, int to=-1)
{
if (from < 0) from = lua_gettop(L) + from + 1;
if (to < 0) to = lua_gettop(L) + to + 1;
lua_pushnil(L);
while (lua_next(L, from) != 0) {
assert(lua_type(L, -1) != LUA_TTABLE);
// duplicate key and value for lua_rawset
lua_pushvalue(L, -2);
lua_pushvalue(L, -2);
lua_rawset(L, to);
lua_pop(L, 1);
}
}
// Pushes the original version of a library function on the stack, from the old version
static inline void push_original(lua_State *L, const char *lib, const char *func)
{
@ -83,7 +98,10 @@ void ScriptApiSecurity::initializeSecurity()
"unpack",
"_VERSION",
"xpcall",
// Completely safe libraries
};
static const char *whitelist_tables[] = {
// These libraries are completely safe BUT we need to duplicate their table
// to ensure the sandbox can't affect the insecure env
"coroutine",
"string",
"table",
@ -167,6 +185,17 @@ void ScriptApiSecurity::initializeSecurity()
lua_pop(L, 1);
// Copy safe libraries
for (const char *libname : whitelist_tables) {
lua_getfield(L, old_globals, libname);
lua_newtable(L);
shallow_copy_table(L);
lua_setglobal(L, libname);
lua_pop(L, 1);
}
// Copy safe IO functions
lua_getfield(L, old_globals, "io");
lua_newtable(L);
@ -222,6 +251,19 @@ void ScriptApiSecurity::initializeSecurity()
#endif
lua_pop(L, 1); // Pop globals_backup
/*
* In addition to copying the tables in whitelist_tables, we also need to
* replace the string metatable. Otherwise old_globals.string would
* be accessible via getmetatable("").__index from inside the sandbox.
*/
lua_pushliteral(L, "");
lua_newtable(L);
lua_getglobal(L, "string");
lua_setfield(L, -2, "__index");
lua_setmetatable(L, -2);
lua_pop(L, 1); // Pop empty string
}
void ScriptApiSecurity::initializeSecurityClient()