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.
This commit is contained in:
Jeija 2016-12-28 10:07:59 +01:00
parent 67cd17aa79
commit 703e6fdadb
2 changed files with 31 additions and 0 deletions

@ -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

@ -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