From 703e6fdadb5251b6f42e35f0f71f3094f5e15f75 Mon Sep 17 00:00:00 2001
From: Jeija <norrepli@gmail.com>
Date: Wed, 28 Dec 2016 10:07:59 +0100
Subject: [PATCH] Luacontroller: Restrict digiline messages

Restrict maximum length of messages to 50.000 characters and disable sending functions or table references over the wire. Restrict types of channel variable to string, number or boolean.

The missing length restriction made DoS-like attacks possible by overflowing memory using string concatenation. Thanks to gamemanj for disclosing this issue.
---
 mesecons/util.lua               | 16 ++++++++++++++++
 mesecons_luacontroller/init.lua | 15 +++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/mesecons/util.lua b/mesecons/util.lua
index 39f5696..0a06401 100644
--- a/mesecons/util.lua
+++ b/mesecons/util.lua
@@ -151,6 +151,22 @@ function mesecon.tablecopy(table) -- deep table copy
 	return newtable
 end
 
+function mesecon.tablecopy_stripfunctions(table) -- deep table copy, but remove all functions
+	if type(table) == "function" then return nil end -- functions become nil
+	if type(table) ~= "table" then return table end -- no need to copy
+	local newtable = {}
+
+	for idx, item in pairs(table) do
+		if type(item) == "table" then
+			newtable[idx] = mesecon.tablecopy(item)
+		elseif type(item) ~= "function" then
+			newtable[idx] = item
+		end
+	end
+
+	return newtable
+end
+
 function mesecon.cmpAny(t1, t2)
 	if type(t1) ~= type(t2) then return false end
 	if type(t1) ~= "table" and type(t2) ~= "table" then return t1 == t2 end
diff --git a/mesecons_luacontroller/init.lua b/mesecons_luacontroller/init.lua
index 7d76b26..3c34887 100644
--- a/mesecons_luacontroller/init.lua
+++ b/mesecons_luacontroller/init.lua
@@ -273,9 +273,23 @@ end
 local function get_digiline_send(pos)
 	if not digiline then return end
 	return function(channel, msg)
+		-- Make sure channel is string, number or boolean
+		if (type(channel) ~= "string" and type(channel) ~= "number" and type(channel) ~= "boolean") then
+			return false
+		end
+
+		-- No sending functions over the wire and make sure serialized version
+		-- of the data is not insanely long to prevent DoS-like attacks
+		msg = mesecon.tablecopy_stripfunctions(msg)
+		local msg_ser = minetest.serialize(msg)
+		if #msg_ser > mesecon.setting("luacontroller_digiline_maxlen", 50000) then
+			return false
+		end
+
 		minetest.after(0, function()
 			digiline:receptor_send(pos, digiline.rules.default, channel, msg)
 		end)
+		return true
 	end
 end
 
@@ -284,6 +298,7 @@ local safe_globals = {
 	"assert", "error", "ipairs", "next", "pairs", "select",
 	"tonumber", "tostring", "type", "unpack", "_VERSION"
 }
+
 local function create_environment(pos, mem, event)
 	-- Gather variables for the environment
 	local vports = minetest.registered_nodes[minetest.get_node(pos).name].virtual_portstates
-- 
GitLab