Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
From 410990bde270c5181643b4aca64a39f2cf232eea Mon Sep 17 00:00:00 2001
From: gfgtdf <daniel.gfgtdf@gmail.com>
Date: Sat, 14 Jul 2018 23:56:42 +0200
Subject: [PATCH] test1
disallow loading lua bytecode via load/dofile
This could otherwise be used to escape the lua sandbox, as described in
multiple sources. For example one can use it to reenable the os.execute
function to do shell commands, but also rop based attacks are possible.
The affected functions were
load,loadstring,wesnoth.dofile,wesnoth.require and various places in the
wesnoth source where lua chunks were loaded for example by the ai code.
This commit also changes the lua source to change luas load (which is
the same as loadstring), alternatively we could add a wrapper around the
original load function that always passes "t" as third parameter, i went
this way mostly because it was easier to implement, but also becasue i
as not 100% sure that is is impossible to change the upvalues of a
function via lua (wesnoth disables debug.setupvalue but still).
---
src/ai/lua/core.cpp | 4 ++--
src/lua/lbaselib.cpp | 5 +++--
src/scripting/lua_fileops.cpp | 2 +-
src/scripting/lua_kernel_base.cpp | 4 +++-
4 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/src/ai/lua/core.cpp b/src/ai/lua/core.cpp
index 303953e2983..3baba3a639b 100644
--- a/src/ai/lua/core.cpp
+++ b/src/ai/lua/core.cpp
@@ -1015,7 +1015,7 @@ static size_t generate_and_push_ai_state(lua_State* L, ai::engine_lua* engine)
lua_ai_context* lua_ai_context::create(lua_State *L, char const *code, ai::engine_lua *engine)
{
- int res_ai = luaL_loadstring(L, code); // [-1: AI code]
+ int res_ai = luaL_loadbufferx(L, code, strlen(code), /*name*/ code, "t"); // [-1: AI code]
if (res_ai != 0)
{
@@ -1057,7 +1057,7 @@ void lua_ai_context::update_state()
lua_ai_action_handler* lua_ai_action_handler::create(lua_State *L, char const *code, lua_ai_context &context)
{
- int res = luaL_loadstring(L, code);//stack size is now 1 [ -1: f]
+ int res = luaL_loadbufferx(L, code, strlen(code), /*name*/ code, "t");//stack size is now 1 [ -1: f]
if (res)
{
char const *m = lua_tostring(L, -1);
diff --git a/src/lua/lbaselib.cpp b/src/lua/lbaselib.cpp
index 6460e4f8d42..c0e73c65b57 100644
--- a/src/lua/lbaselib.cpp
+++ b/src/lua/lbaselib.cpp
@@ -336,16 +336,17 @@ static int luaB_load (lua_State *L) {
size_t l;
const char *s = lua_tolstring(L, 1, &l);
const char *mode = luaL_optstring(L, 3, "bt");
+ (void) mode;
int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */
if (s != NULL) { /* loading a string? */
const char *chunkname = luaL_optstring(L, 2, s);
- status = luaL_loadbufferx(L, s, l, chunkname, mode);
+ status = luaL_loadbufferx(L, s, l, chunkname, "t");
}
else { /* loading from a reader function */
const char *chunkname = luaL_optstring(L, 2, "=(load)");
luaL_checktype(L, 1, LUA_TFUNCTION);
lua_settop(L, RESERVEDSLOT); /* create reserved slot */
- status = lua_load(L, generic_reader, NULL, chunkname, mode);
+ status = lua_load(L, generic_reader, NULL, chunkname, "t");
}
return load_aux(L, status, env);
}
diff --git a/src/scripting/lua_fileops.cpp b/src/scripting/lua_fileops.cpp
index 0016df0d202..88320b4c6ef 100644
--- a/src/scripting/lua_fileops.cpp
+++ b/src/scripting/lua_fileops.cpp
@@ -217,7 +217,7 @@ class lua_filestream
//lua uses '@' to know that this is a file (as opposed to something loaded via loadstring )
std::string chunkname = '@' + relativename;
LOG_LUA << "starting to read from " << fname << "\n";
- return lua_load(L, &lua_filestream::lua_read_data, &lfs, chunkname.c_str(), nullptr);
+ return lua_load(L, &lua_filestream::lua_read_data, &lfs, chunkname.c_str(), "t");
}
private:
char buff_[LUAL_BUFFERSIZE];
diff --git a/src/scripting/lua_kernel_base.cpp b/src/scripting/lua_kernel_base.cpp
index 0a2db78cb90..4111e738381 100644
--- a/src/scripting/lua_kernel_base.cpp
+++ b/src/scripting/lua_kernel_base.cpp
@@ -675,7 +675,9 @@ bool lua_kernel_base::protected_call(lua_State * L, int nArgs, int nRets, error_
bool lua_kernel_base::load_string(char const * prog, error_handler e_h)
{
- int errcode = luaL_loadstring(mState, prog);
+ // pass 't' to prevent loading bytecode which is unsafe and can be used to escape the sandbox.
+ // todo: maybe allow a 'name' parameter to give better error messages.
+ int errcode = luaL_loadbufferx(mState, prog, strlen(prog), /*name*/ prog, "t");
if (errcode != LUA_OK) {
char const * msg = lua_tostring(mState, -1);
std::string message = msg ? msg : "null string";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.