In my project I'm executing some lua functions contained in an XML file. I read the XML from C++, parse the code strings, execute them and get the result.
All of the related questions I have found either used a dedicated .lua
file or did it in Lua directly and I couldn't find a solution that worked for my case.
I can't modify the functions in the file and they all have the following signature:
function() --or function ()
--do stuff
return foo
end
from C++ i load them like so:
lua_State *L = luaL_newstate();
luaL_openlibs(L);
std::string code = get_code_from_XML();
std::string wrapped_code = "return " + code;
luaL_loadstring(L, wrapped_code.c_str());
if (lua_pcall(L, 0, 1, 0)){
return 1;
}
argNum = load_arg_number();
if (lua_pcall(L, argNum, 1, 0)){
return 1;
}
return 0;
Everything works but running arbitrary Lua code from an XML string doesn't seem very safe so i wanted to set up a whitelist of functions that the code can use.
Following this lua-users discussion i created my list of allowed functions like:
// Of course my list is bigger
std::string whitelist = "sandbox_env = {ipairs = ipairs} _ENV = sandbox_env"
The problem is that I don't understand how to load it to be available in the functions that I'm calling.
I tried doing it like on the lua-users website:
std::string Lua_sandboxed_script_to_run( Lua_sandboxing_script + Lua_script_to_run ) if (luaL_dostring(sandboxed_L, Lua_sandboxed_script_to_run)) { // error checking }
But this results in the function not being loaded correctly and the Lua error
Trying to execute a string value
I also tried to do:
luaL_loadstring(L, whitelist.c_str());
lua_getglobal(L, "_ENV");
lua_setupvalue(L, -2, 1);
Before executing the loaded XML function, this doesn't crash the program but doesn't set the _ENV
for the called function either.
The only way I have found to have what I want is to parse the function string with C++ searching for ()
, insert whitelist
after it and then luaL_loadstring
and lua_pcall
it twice to execute it.
Like this:
.
.
size_t n = code.find("()") + 2;
code.insert(n, whitelist);
std::string wrapped_code = "return " + code;
.
.
This works and sets my custom _ENV for the function but seems to me like a really hacky way to go about it.
How can I set the _ENV variable for a string function loaded from C in a nicer way?
Bonus points if there is a way to save it once for the whole lua_State
instead of every time I call a function.