lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]



I've been using Lua 5.1 for a few years as a configuration and extension
language for our C++ programs at my work. We have a C++ wrapper
interface that sandboxes the lua script that's loaded from file or
string, and also provides a sandboxed interface to calling out to lua
functions where desired. 

The original ideas for the sandbox were derived from my reading
of the various Lua literature available a few years ago when Lua 5.1
was the current release.

I'm seeking advice on the best way to use Lua 5.2 from C/C++
to load chunks in a sandboxed environment and subsequently invoke
lua functions from C/C++ in that same sandbox.

With the change in Lua 5.2 to deprecate lua_setfenv() in favour of other
techniques (upvalues ?), I would like to update the C++ wrapper library
for Lua 5.2/5.3 as well as continuing to support Lua 5.1.

It may be that the pattern I used for Lua 5.1 can't be used for Lua 5.2
and I need to redesign my wrapper library. I'd prefer to do that in a
way that reduces change on callers of the library.

Current use in Lua 5.1:

The sandboxing setup technique used in Lua 5.1 is:
	a) create a table for the environment
	b) copy names of "safe" globals into the table, such as
	   assert(), ipairs(), string.*, (etc)
	c) add other (private) extensions to the table
	d) add the table to the global environment with a well-known name

To invoke a chunk or function 
	a) limit instructions / maskcount
	b) get the sandbox table from the global environment
	c) set the environment for the chunk/function with lua_setfenv()
	d) call the chunk/function

To lookup a table value (e.g. to obtain t1.t2 from "t1 = { t2 = 5, }")
methods to obtain the values by traversing the sandbox table.

This has been working well for a few years.

Attempt to convert to Lua 5.2:

I've tried converting our use of lua_setfenv() to lua_setupvalue() but
it's not setting up the environment correctly when trying to set
the environment for a function call (versus a chunk call).
lua_setupvalue(L, -3, 1) is returning NULL when the stack has;
	1: function
	2: table as function argument
	3: table to use as environment

I.e. When I change Lua 5.1's
	lua_setfenv(L, -iNumArgs - 2))
to Lua 5.2's
	lua_setupvalue(L, -iNumArgs - 2, 1)
my sandboxing doesn't work.

Pseudo-code of the Lua 5.1 sandbox technique:

// Construct state
lua_State * setup()
	lua_State * L = luaL_newstate();
		// sandbox will get a subset of the libs
	return L;

// Load string onto stack
loadstring(lua_state * L, const char * str)	// (loadfile is similar)
	luaL_loadstring(L, str)

// Setup sandbox and call chunk on the stack
callChunk(lua_state * LL)
	lua_newtable(L)				// populate table for sandbox
	lua_setglobal(L, "LuaSandbox");		// store sandbox in global var
	sandboxCall(L, 0, 0)

// Call function on stack in a sandbox (maskcount, restricted environment)
sandboxCall(lua_state * L, int iNumArgs, int iNumResults)
	lua_sethook(L, &maskcount, LUA_MASKCOUNT, someLimit);
	lua_getglobal(L, "LuaSandBox");		// set environment to sandbox
	lua_setfenv(L, -iNumArgs - 2);
	lua_pcall(L, iNumArgs, iNumResults);
	lua_sethook(L, &maskcount, LUA_MASKCOUNT, 0);

// Setup table for use as a sandbox environment. Caller may extend.
setupSandbox(lua_State * L)
	// copy values from global environment into sandbox table on stack top

// Call a lua function from C that takes a table argument & returns a bool
fooFunction(lua_State * L)
	findName(L, "some_method");
	if (! lua_isfunction(L, -1)) error();
	lua_createTable(L, 0, 1);
	lua_pushstring(L, "some value");
	lua_setfield(L, "k");		// { k = "somevalue", }
	sandboxCall(L, 1, 1)		// invoke some_method({k="somevalue"})
	bool result = lua_toboolean(L, -1)
	lua_pop(L, 1);
	return result;


Attachment: pgpgfZE4qar5_.pgp
Description: PGP signature