Skip to content

Commit b2409b1

Browse files
committedDec 18, 2021
Refactor trusted mod checking code
1 parent f405459 commit b2409b1

File tree

4 files changed

+46
-72
lines changed

4 files changed

+46
-72
lines changed
 

‎src/script/cpp_api/s_security.cpp

+33
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
2727

2828
#include <cerrno>
2929
#include <string>
30+
#include <algorithm>
3031
#include <iostream>
3132

3233

@@ -604,6 +605,38 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path,
604605
return false;
605606
}
606607

608+
bool ScriptApiSecurity::checkWhitelisted(lua_State *L, const std::string &setting)
609+
{
610+
assert(str_starts_with(setting, "secure."));
611+
612+
// We have to make sure that this function is being called directly by
613+
// a mod, otherwise a malicious mod could override this function and
614+
// steal its return value.
615+
lua_Debug info;
616+
617+
// Make sure there's only one item below this function on the stack...
618+
if (lua_getstack(L, 2, &info))
619+
return false;
620+
FATAL_ERROR_IF(!lua_getstack(L, 1, &info), "lua_getstack() failed");
621+
FATAL_ERROR_IF(!lua_getinfo(L, "S", &info), "lua_getinfo() failed");
622+
623+
// ...and that that item is the main file scope.
624+
if (strcmp(info.what, "main") != 0)
625+
return false;
626+
627+
// Mod must be listed in secure.http_mods or secure.trusted_mods
628+
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
629+
if (!lua_isstring(L, -1))
630+
return false;
631+
std::string mod_name = readParam<std::string>(L, -1);
632+
633+
std::string value = g_settings->get(setting);
634+
value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
635+
auto mod_list = str_split(value, ',');
636+
637+
return CONTAINS(mod_list, mod_name);
638+
}
639+
607640

608641
int ScriptApiSecurity::sl_g_dofile(lua_State *L)
609642
{

‎src/script/cpp_api/s_security.h

+9-5
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
4040
class ScriptApiSecurity : virtual public ScriptApiBase
4141
{
4242
public:
43-
int getThread(lua_State *L);
44-
// creates an empty Lua environment
45-
void createEmptyEnv(lua_State *L);
46-
// sets the enviroment to the table thats on top of the stack
47-
void setLuaEnv(lua_State *L, int thread);
4843
// Sets up security on the ScriptApi's Lua state
4944
void initializeSecurity();
5045
void initializeSecurityClient();
@@ -57,8 +52,17 @@ class ScriptApiSecurity : virtual public ScriptApiBase
5752
// Checks if mods are allowed to read (and optionally write) to the path
5853
static bool checkPath(lua_State *L, const char *path, bool write_required,
5954
bool *write_allowed=NULL);
55+
// Check if mod is whitelisted in the given setting
56+
// This additionally checks that the mod's main file scope is executing.
57+
static bool checkWhitelisted(lua_State *L, const std::string &setting);
6058

6159
private:
60+
int getThread(lua_State *L);
61+
// sets the enviroment to the table thats on top of the stack
62+
void setLuaEnv(lua_State *L, int thread);
63+
// creates an empty Lua environment
64+
void createEmptyEnv(lua_State *L);
65+
6266
// Syntax: "sl_" <Library name or 'g' (global)> '_' <Function name>
6367
// (sl stands for Secure Lua)
6468

‎src/script/lua_api/l_http.cpp

+3-36
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
2121
#include "common/c_converter.h"
2222
#include "common/c_content.h"
2323
#include "lua_api/l_http.h"
24+
#include "cpp_api/s_security.h"
2425
#include "httpfetch.h"
2526
#include "settings.h"
2627
#include "debug.h"
2728
#include "log.h"
2829

29-
#include <algorithm>
3030
#include <iomanip>
31-
#include <cctype>
3231

3332
#define HTTP_API(name) \
3433
lua_pushstring(L, #name); \
@@ -181,40 +180,8 @@ int ModApiHttp::l_request_http_api(lua_State *L)
181180
{
182181
NO_MAP_LOCK_REQUIRED;
183182

184-
// We have to make sure that this function is being called directly by
185-
// a mod, otherwise a malicious mod could override this function and
186-
// steal its return value.
187-
lua_Debug info;
188-
189-
// Make sure there's only one item below this function on the stack...
190-
if (lua_getstack(L, 2, &info)) {
191-
return 0;
192-
}
193-
FATAL_ERROR_IF(!lua_getstack(L, 1, &info), "lua_getstack() failed");
194-
FATAL_ERROR_IF(!lua_getinfo(L, "S", &info), "lua_getinfo() failed");
195-
196-
// ...and that that item is the main file scope.
197-
if (strcmp(info.what, "main") != 0) {
198-
return 0;
199-
}
200-
201-
// Mod must be listed in secure.http_mods or secure.trusted_mods
202-
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
203-
if (!lua_isstring(L, -1)) {
204-
return 0;
205-
}
206-
207-
std::string mod_name = readParam<std::string>(L, -1);
208-
std::string http_mods = g_settings->get("secure.http_mods");
209-
http_mods.erase(std::remove(http_mods.begin(), http_mods.end(), ' '), http_mods.end());
210-
std::vector<std::string> mod_list_http = str_split(http_mods, ',');
211-
212-
std::string trusted_mods = g_settings->get("secure.trusted_mods");
213-
trusted_mods.erase(std::remove(trusted_mods.begin(), trusted_mods.end(), ' '), trusted_mods.end());
214-
std::vector<std::string> mod_list_trusted = str_split(trusted_mods, ',');
215-
216-
mod_list_http.insert(mod_list_http.end(), mod_list_trusted.begin(), mod_list_trusted.end());
217-
if (std::find(mod_list_http.begin(), mod_list_http.end(), mod_name) == mod_list_http.end()) {
183+
if (!ScriptApiSecurity::checkWhitelisted(L, "secure.http_mods") &&
184+
!ScriptApiSecurity::checkWhitelisted(L, "secure.trusted_mods")) {
218185
lua_pushnil(L);
219186
return 1;
220187
}

‎src/script/lua_api/l_util.cpp

+1-31
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
4141
#include "util/hex.h"
4242
#include "util/sha1.h"
4343
#include "util/png.h"
44-
#include <algorithm>
4544
#include <cstdio>
4645

4746
// log([level,] text)
@@ -444,36 +443,7 @@ int ModApiUtil::l_request_insecure_environment(lua_State *L)
444443
return 1;
445444
}
446445

447-
// We have to make sure that this function is being called directly by
448-
// a mod, otherwise a malicious mod could override this function and
449-
// steal its return value.
450-
lua_Debug info;
451-
// Make sure there's only one item below this function on the stack...
452-
if (lua_getstack(L, 2, &info)) {
453-
return 0;
454-
}
455-
FATAL_ERROR_IF(!lua_getstack(L, 1, &info), "lua_getstack() failed");
456-
FATAL_ERROR_IF(!lua_getinfo(L, "S", &info), "lua_getinfo() failed");
457-
// ...and that that item is the main file scope.
458-
if (strcmp(info.what, "main") != 0) {
459-
return 0;
460-
}
461-
462-
// Get mod name
463-
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
464-
if (!lua_isstring(L, -1)) {
465-
return 0;
466-
}
467-
468-
// Check secure.trusted_mods
469-
std::string mod_name = readParam<std::string>(L, -1);
470-
std::string trusted_mods = g_settings->get("secure.trusted_mods");
471-
trusted_mods.erase(std::remove_if(trusted_mods.begin(),
472-
trusted_mods.end(), static_cast<int(*)(int)>(&std::isspace)),
473-
trusted_mods.end());
474-
std::vector<std::string> mod_list = str_split(trusted_mods, ',');
475-
if (std::find(mod_list.begin(), mod_list.end(), mod_name) ==
476-
mod_list.end()) {
446+
if (!ScriptApiSecurity::checkWhitelisted(L, "secure.trusted_mods")) {
477447
return 0;
478448
}
479449

0 commit comments

Comments
 (0)
Please sign in to comment.