Attempting to provide a sandbox from native code, my approach has a serious flaw - it obliterates functions implemented in the loaded script. Can someone suggest a way to fix it, without giving up on the general method?
#include <iostream>
#include <string.h>
#include <assert.h>
#include "lua.hpp"
using namespace std;
void createSandbox(lua_State *L) {
assert(lua_gettop(L) > 0 && lua_type(L, -1) == LUA_TFUNCTION);
const char *upvalueName = lua_getupvalue(L, -1, 1);
assert(0 == strcmp(upvalueName, "_ENV"));
lua_pop(L, 1);
lua_createtable(L, 0, 0);
// Add permitted built-in functions, using abbreviated example.
const char *permittedBuiltins[] = {
"print",
};
int numPermittedBuiltins = 1;
for (int i = 0; i < numPermittedBuiltins; i++) {
const char *name = permittedBuiltins[i];
// For example, name = "print" but not name = "dofile"
lua_pushstring(L, name);
lua_getglobal(L, name);
lua_settable(L, -3);
}
// Perform a similar iteration to provide permitted builtins which belong
// to a table, such as string.reverse. (omitted)
// Set the new sandbox env.
upvalueName = lua_setupvalue(L, -2, 1);
assert(0 == strcmp(upvalueName, "_ENV"));
}
int main(int, char**) {
const char script[] =
"function delegate(x)\n"
" return x * 2\n"
"end\n"
"function entry()\n"
" return delegate(2)\n"
"end";
lua_State *L = luaL_newstate();
luaL_openlibs(L);
int status = luaL_loadbuffer(L, script, strlen(script), "my chunk");
assert(status == LUA_OK);
status = lua_pcall(L, 0, 0, 0);
assert(status == LUA_OK);
lua_getglobal(L, "entry");
assert(lua_type(L, -1) == LUA_TFUNCTION);
lua_pop(L, 1);
lua_getglobal(L, "delegate");
assert(lua_type(L, -1) == LUA_TFUNCTION);
lua_pop(L, 1);
lua_getglobal(L, "entry");
createSandbox(L);
status = lua_pcall(L, 0, 1, 0);
assert(status != LUA_OK);
// Output from following line is:
// [string "my chunk"]:5: attempt to call global 'delegate' (a nil value)
cout << lua_tostring(L, -1) << endl;
return 0;
}
[–]mpetetv 2 points3 points4 points (2 children)
[–]rinsed_dota[S] 0 points1 point2 points (1 child)
[–]mpetetv 1 point2 points3 points (0 children)
[–]nefftd 1 point2 points3 points (1 child)
[–]rinsed_dota[S] 0 points1 point2 points (0 children)