Create a sandboxed VM: curated stdlib, os/coroutine/debug/setfenv/getfenv dropped, the shared stdlib frozen read-only (luaL_sandbox), then a fresh per-VM writable global table layered on top (luaL_sandboxthread). Net effect: a filter can assign its own top-level globals for persistent state, but cannot mutate the stdlib or leak globals into a sibling filter's VM. Also installs a memory cap + watch
| 95 | // left OPEN during trusted setup (openlibs/sandbox) and clamped to limits.mem_bytes |
| 96 | // only once setup is done, so a small cap can never make setup fail/abort. |
| 97 | lua_State* newSandboxedState(BudgetState* budget, const BudgetLimits& limits) { |
| 98 | budget->used = 0; |
| 99 | budget->max_bytes = std::numeric_limits<std::size_t>::max(); // no cap during setup |
| 100 | armFuel(budget, limits.setup_fuel); |
| 101 | lua_State* L = lua_newstate(budgetAlloc, budget); |
| 102 | if (L == nullptr) { |
| 103 | return nullptr; |
| 104 | } |
| 105 | luaL_openlibs(L); |
| 106 | // Drop capabilities filters never need; setfenv/getfenv would let a script swap |
| 107 | // its environment and escape the per-VM globals table back onto the frozen |
| 108 | // stdlib (or another scope), defeating the sandbox isolation set up below. |
| 109 | for (const char* lib : {"os", "coroutine", "debug", "setfenv", "getfenv"}) { |
| 110 | lua_pushnil(L); |
| 111 | lua_setglobal(L, lib); |
| 112 | } |
| 113 | luaL_sandbox(L); // freeze the shared stdlib read-only |
| 114 | // Own writable global table for this VM (frozen stdlib as read-only __index): |
| 115 | // top-level globals the script assigns land here, stdlib reads fall through. |
| 116 | // One module loads per VM, so safeenv stays on and imports keep the fast path. |
| 117 | luaL_sandboxthread(L); |
| 118 | lua_callbacks(L)->userdata = budget; |
| 119 | lua_callbacks(L)->interrupt = budgetInterrupt; |
| 120 | budget->max_bytes = limits.mem_bytes; // cap now applies to all untrusted execution |
| 121 | return L; |
| 122 | } |
| 123 | |
| 124 | // ---- small stack helpers ------------------------------------------------- |
| 125 |
no test coverage detected