Don't let HTTP API pass through untrusted function

This has been a problem since the first day, oops.
This commit is contained in:
sfan5 2021-12-17 18:31:29 +01:00
parent 8472141b79
commit 8c99f2232b
4 changed files with 27 additions and 6 deletions

@ -250,7 +250,7 @@ end
-- HTTP callback interface -- HTTP callback interface
function core.http_add_fetch(httpenv) core.set_http_api_lua(function(httpenv)
httpenv.fetch = function(req, callback) httpenv.fetch = function(req, callback)
local handle = httpenv.fetch_async(req) local handle = httpenv.fetch_async(req)
@ -266,7 +266,8 @@ function core.http_add_fetch(httpenv)
end end
return httpenv return httpenv
end end)
core.set_http_api_lua = nil
function core.close_formspec(player_name, formname) function core.close_formspec(player_name, formname)

@ -54,6 +54,8 @@ extern "C" {
#define CUSTOM_RIDX_GLOBALS_BACKUP (CUSTOM_RIDX_BASE + 1) #define CUSTOM_RIDX_GLOBALS_BACKUP (CUSTOM_RIDX_BASE + 1)
#define CUSTOM_RIDX_CURRENT_MOD_NAME (CUSTOM_RIDX_BASE + 2) #define CUSTOM_RIDX_CURRENT_MOD_NAME (CUSTOM_RIDX_BASE + 2)
#define CUSTOM_RIDX_BACKTRACE (CUSTOM_RIDX_BASE + 3) #define CUSTOM_RIDX_BACKTRACE (CUSTOM_RIDX_BASE + 3)
#define CUSTOM_RIDX_HTTP_API_LUA (CUSTOM_RIDX_BASE + 4)
// Determine if CUSTOM_RIDX_SCRIPTAPI will hold a light or full userdata // Determine if CUSTOM_RIDX_SCRIPTAPI will hold a light or full userdata
#if defined(__aarch64__) && USE_LUAJIT #if defined(__aarch64__) && USE_LUAJIT

@ -163,6 +163,20 @@ int ModApiHttp::l_http_fetch_async_get(lua_State *L)
return 1; return 1;
} }
int ModApiHttp::l_set_http_api_lua(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
// This is called by builtin to give us a function that will later
// populate the http_api table with additional method(s).
// We need this because access to the HTTP api is security-relevant and
// any mod could just mess with a global variable.
luaL_checktype(L, 1, LUA_TFUNCTION);
lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_HTTP_API_LUA);
return 0;
}
int ModApiHttp::l_request_http_api(lua_State *L) int ModApiHttp::l_request_http_api(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
@ -205,16 +219,16 @@ int ModApiHttp::l_request_http_api(lua_State *L)
return 1; return 1;
} }
lua_getglobal(L, "core"); lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_HTTP_API_LUA);
lua_getfield(L, -1, "http_add_fetch"); assert(lua_isfunction(L, -1));
lua_newtable(L); lua_newtable(L);
HTTP_API(fetch_async); HTTP_API(fetch_async);
HTTP_API(fetch_async_get); HTTP_API(fetch_async_get);
// Stack now looks like this: // Stack now looks like this:
// <core.http_add_fetch> <table with fetch_async, fetch_async_get> // <function> <table with fetch_async, fetch_async_get>
// Now call core.http_add_fetch to append .fetch(request, callback) to table // Now call it to append .fetch(request, callback) to table
lua_call(L, 1, 1); lua_call(L, 1, 1);
return 1; return 1;
@ -247,6 +261,7 @@ void ModApiHttp::Initialize(lua_State *L, int top)
API_FCT(get_http_api); API_FCT(get_http_api);
} else { } else {
API_FCT(request_http_api); API_FCT(request_http_api);
API_FCT(set_http_api_lua);
} }
#endif #endif

@ -41,6 +41,9 @@ private:
// http_fetch_async_get(handle) // http_fetch_async_get(handle)
static int l_http_fetch_async_get(lua_State *L); static int l_http_fetch_async_get(lua_State *L);
// set_http_api_lua() [internal]
static int l_set_http_api_lua(lua_State *L);
// request_http_api() // request_http_api()
static int l_request_http_api(lua_State *L); static int l_request_http_api(lua_State *L);