Refactor loading of Lua code with mod security

This commit is contained in:
sfan5 2019-11-08 18:35:32 +01:00
parent 17191a60fb
commit 5ab546f99b
2 changed files with 28 additions and 52 deletions
src/script/cpp_api

@ -372,14 +372,16 @@ bool ScriptApiSecurity::isSecure(lua_State *L)
return secure; return secure;
} }
bool ScriptApiSecurity::safeLoadString(lua_State *L, const std::string &code, const char *chunk_name)
#define CHECK_FILE_ERR(ret, fp) \ {
if (ret) { \ if (code.size() > 0 && code[0] == LUA_SIGNATURE[0]) {
lua_pushfstring(L, "%s: %s", path, strerror(errno)); \ lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
if (fp) std::fclose(fp); \ return false;
return false; \
} }
if (luaL_loadbuffer(L, code.data(), code.size(), chunk_name))
return false;
return true;
}
bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char *display_name) bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char *display_name)
{ {
@ -406,68 +408,49 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char
int c = std::getc(fp); int c = std::getc(fp);
if (c == '#') { if (c == '#') {
// Skip the first line // Skip the first line
while ((c = std::getc(fp)) != EOF && c != '\n'); while ((c = std::getc(fp)) != EOF && c != '\n') {}
if (c == '\n') c = std::getc(fp); if (c == '\n')
std::getc(fp);
start = std::ftell(fp); start = std::ftell(fp);
} }
if (c == LUA_SIGNATURE[0]) {
lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
std::fclose(fp);
if (path) {
delete [] chunk_name;
}
return false;
}
// Read the file // Read the file
int ret = std::fseek(fp, 0, SEEK_END); int ret = std::fseek(fp, 0, SEEK_END);
if (ret) { if (ret) {
lua_pushfstring(L, "%s: %s", path, strerror(errno)); lua_pushfstring(L, "%s: %s", path, strerror(errno));
std::fclose(fp);
if (path) { if (path) {
std::fclose(fp);
delete [] chunk_name; delete [] chunk_name;
} }
return false; return false;
} }
size_t size = std::ftell(fp) - start; size_t size = std::ftell(fp) - start;
char *code = new char[size]; std::string code(size, '\0');
ret = std::fseek(fp, start, SEEK_SET); ret = std::fseek(fp, start, SEEK_SET);
if (ret) { if (ret) {
lua_pushfstring(L, "%s: %s", path, strerror(errno)); lua_pushfstring(L, "%s: %s", path, strerror(errno));
std::fclose(fp);
delete [] code;
if (path) { if (path) {
std::fclose(fp);
delete [] chunk_name; delete [] chunk_name;
} }
return false; return false;
} }
size_t num_read = std::fread(code, 1, size, fp); size_t num_read = std::fread(&code[0], 1, size, fp);
if (path) { if (path)
std::fclose(fp); std::fclose(fp);
}
if (num_read != size) { if (num_read != size) {
lua_pushliteral(L, "Error reading file to load."); lua_pushliteral(L, "Error reading file to load.");
delete [] code; if (path)
if (path) {
delete [] chunk_name; delete [] chunk_name;
}
return false; return false;
} }
if (luaL_loadbuffer(L, code, size, chunk_name)) { bool result = safeLoadString(L, code, chunk_name);
delete [] code; if (path)
return false;
}
delete [] code;
if (path) {
delete [] chunk_name; delete [] chunk_name;
} return result;
return true;
} }
@ -628,14 +611,9 @@ int ScriptApiSecurity::sl_g_load(lua_State *L)
code += std::string(buf, len); code += std::string(buf, len);
lua_pop(L, 1); // Pop return value lua_pop(L, 1); // Pop return value
} }
if (code[0] == LUA_SIGNATURE[0]) { if (!safeLoadString(L, code, chunk_name)) {
lua_pushnil(L); lua_pushnil(L);
lua_pushliteral(L, "Bytecode prohibited when mod security is enabled."); lua_insert(L, -2);
return 2;
}
if (luaL_loadbuffer(L, code.data(), code.size(), chunk_name)) {
lua_pushnil(L);
lua_insert(L, lua_gettop(L) - 1);
return 2; return 2;
} }
return 1; return 1;
@ -694,15 +672,11 @@ int ScriptApiSecurity::sl_g_loadstring(lua_State *L)
size_t size; size_t size;
const char *code = lua_tolstring(L, 1, &size); const char *code = lua_tolstring(L, 1, &size);
std::string code_s(code, size);
if (size > 0 && code[0] == LUA_SIGNATURE[0]) { if (!safeLoadString(L, code_s, chunk_name)) {
lua_pushnil(L); lua_pushnil(L);
lua_pushliteral(L, "Bytecode prohibited when mod security is enabled."); lua_insert(L, -2);
return 2;
}
if (luaL_loadbuffer(L, code, size, chunk_name)) {
lua_pushnil(L);
lua_insert(L, lua_gettop(L) - 1);
return 2; return 2;
} }
return 1; return 1;

@ -50,6 +50,8 @@ public:
void initializeSecurityClient(); void initializeSecurityClient();
// Checks if the Lua state has been secured // Checks if the Lua state has been secured
static bool isSecure(lua_State *L); static bool isSecure(lua_State *L);
// Loads a string as Lua code safely (doesn't allow bytecode).
static bool safeLoadString(lua_State *L, const std::string &code, const char *chunk_name);
// Loads a file as Lua code safely (doesn't allow bytecode). // Loads a file as Lua code safely (doesn't allow bytecode).
static bool safeLoadFile(lua_State *L, const char *path, const char *display_name = NULL); static bool safeLoadFile(lua_State *L, const char *path, const char *display_name = NULL);
// Checks if mods are allowed to read (and optionally write) to the path // Checks if mods are allowed to read (and optionally write) to the path