Skip to content

Commit

Permalink
Require request_insecure_environment to be called from the mod's main…
Browse files Browse the repository at this point in the history
… scope

Previously you could steal a secure environment from a trusted mod by wrapping
request_insecure_environment with some code like this:

local rie_cp = minetest.request_insecure_environment
local stolen_ie
function minetest.request_insecure_environment()
	local ie = rie_cp()
	stolen_ie = stolen_ie or ie
	return ie
end
  • Loading branch information
ShadowNinja authored and paramat committed Feb 19, 2016
1 parent 997be66 commit 4827ee1
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 6 deletions.
2 changes: 1 addition & 1 deletion doc/lua_api.txt
Expand Up @@ -2437,7 +2437,7 @@ These functions return the leftover itemstack.
* `minetest.request_insecure_environment()`: returns an environment containing
insecure functions if the calling mod has been listed as trusted in the
`secure.trusted_mods` setting or security is disabled, otherwise returns `nil`.
* Only works at init time.
* Only works at init time and must be called from the mod's main scope (not from a function).
* **DO NOT ALLOW ANY OTHER MODS TO ACCESS THE RETURNED ENVIRONMENT, STORE IT IN
A LOCAL VARIABLE!**

Expand Down
32 changes: 27 additions & 5 deletions src/script/lua_api/l_util.cpp
Expand Up @@ -357,22 +357,44 @@ int ModApiUtil::l_get_dir_list(lua_State *L)
int ModApiUtil::l_request_insecure_environment(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;

// Just return _G if security is disabled
if (!ScriptApiSecurity::isSecure(L)) {
lua_getglobal(L, "_G");
return 1;
}

// We have to make sure that this function is being called directly by
// a mod, otherwise a malicious mod could override this function and
// steal its return value.
lua_Debug info;
// Make sure there's only one item below this function on the stack...
if (lua_getstack(L, 2, &info)) {
return 0;
}
assert(lua_getstack(L, 1, &info));
assert(lua_getinfo(L, "S", &info));
// ...and that that item is the main file scope.
if (strcmp(info.what, "main") != 0) {
return 0;
}

// Get mod name
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
if (!lua_isstring(L, -1)) {
lua_pushnil(L);
return 1;
return 0;
}

// Check secure.trusted_mods
const char *mod_name = lua_tostring(L, -1);
std::string trusted_mods = g_settings->get("secure.trusted_mods");
std::vector<std::string> mod_list = str_split(trusted_mods, ',');
if (std::find(mod_list.begin(), mod_list.end(), mod_name) == mod_list.end()) {
lua_pushnil(L);
return 1;
if (std::find(mod_list.begin(), mod_list.end(), mod_name) ==
mod_list.end()) {
return 0;
}

// Push insecure environment
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
return 1;
}
Expand Down

2 comments on commit 4827ee1

@gaelysam
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So minetest.request_insecure_environment can only be called from init.lua ?

@est31
Copy link
Contributor

@est31 est31 commented on 4827ee1 Feb 19, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, unfortunately there is no other way :(

Please sign in to comment.