forked from Mirrorlandia_minetest/mesecons
Disable JIT optimization for user code and allow string.find in plain mode
Disabling LuaJIT for user code enables normal working of debug.sethook() even for loops. The drawback is that that code will run more slowly. The fourth parameter of string.find indicates whether the second parameter should be interpreted literally (true) or as a pattern (false). Allowing patterns enables DoS attacks, but it's possible to allow literal matching with little effort, by disallowing the function only if the fourth parameter (plain mode) is not `true`.
This commit is contained in:
parent
72e513ecbd
commit
b487783c23
@ -216,6 +216,17 @@ local function safe_string_rep(str, n)
|
|||||||
return string.rep(str, n)
|
return string.rep(str, n)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- string.find with a pattern can be used to DoS the server.
|
||||||
|
-- Therefore, limit string.find to patternless matching.
|
||||||
|
local function safe_string_find(...)
|
||||||
|
if (select(4, ...)) ~= true then
|
||||||
|
debug.sethook() -- Clear hook
|
||||||
|
error("string.find: 'plain' (fourth parameter) must always be true in a LuaController")
|
||||||
|
end
|
||||||
|
|
||||||
|
return string.find(...)
|
||||||
|
end
|
||||||
|
|
||||||
local function remove_functions(x)
|
local function remove_functions(x)
|
||||||
local tp = type(x)
|
local tp = type(x)
|
||||||
if tp == "table" then
|
if tp == "table" then
|
||||||
@ -292,6 +303,7 @@ local function create_environment(pos, mem, event)
|
|||||||
rep = safe_string_rep,
|
rep = safe_string_rep,
|
||||||
reverse = string.reverse,
|
reverse = string.reverse,
|
||||||
sub = string.sub,
|
sub = string.sub,
|
||||||
|
find = safe_string_find,
|
||||||
},
|
},
|
||||||
math = {
|
math = {
|
||||||
abs = math.abs,
|
abs = math.abs,
|
||||||
@ -354,22 +366,6 @@ local function timeout()
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function code_prohibited(code)
|
|
||||||
-- LuaJIT doesn't increment the instruction counter when running
|
|
||||||
-- loops, so we have to sanitize inputs if we're using LuaJIT.
|
|
||||||
if not rawget(_G, "jit") then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
local prohibited = {"while", "for", "repeat", "until", "goto"}
|
|
||||||
code = " "..code.." "
|
|
||||||
for _, p in ipairs(prohibited) do
|
|
||||||
if string.find(code, "[^%w_]"..p.."[^%w_]") then
|
|
||||||
return "Prohibited command: "..p
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function create_sandbox(code, env)
|
local function create_sandbox(code, env)
|
||||||
if code:byte(1) == 27 then
|
if code:byte(1) == 27 then
|
||||||
return nil, "Binary code prohibited."
|
return nil, "Binary code prohibited."
|
||||||
@ -378,24 +374,17 @@ local function create_sandbox(code, env)
|
|||||||
if not f then return nil, msg end
|
if not f then return nil, msg end
|
||||||
setfenv(f, env)
|
setfenv(f, env)
|
||||||
|
|
||||||
|
-- Turn off JIT optimization for user code so that count
|
||||||
|
-- events are generated when adding debug hooks
|
||||||
|
if rawget(_G, "jit") then
|
||||||
|
jit.off(f, true)
|
||||||
|
end
|
||||||
|
|
||||||
return function(...)
|
return function(...)
|
||||||
-- Normal Lua: Use instruction counter to stop execution
|
-- Use instruction counter to stop execution
|
||||||
-- after luacontroller_maxevents.
|
-- after luacontroller_maxevents
|
||||||
-- LuaJIT: Count function calls instead of instructions, allows usage
|
|
||||||
-- of function keyword. However, LuaJIT still doesn't trigger
|
|
||||||
-- lines events when using infinite loops.
|
|
||||||
local maxevents = mesecon.setting("luacontroller_maxevents", 10000)
|
local maxevents = mesecon.setting("luacontroller_maxevents", 10000)
|
||||||
if not rawget(_G, "jit") then
|
debug.sethook(timeout, "", maxevents)
|
||||||
debug.sethook(timeout, "", maxevents)
|
|
||||||
else
|
|
||||||
local events = 0
|
|
||||||
debug.sethook(function ()
|
|
||||||
events = events + 1
|
|
||||||
if events > maxevents then
|
|
||||||
timeout()
|
|
||||||
end
|
|
||||||
end, "c")
|
|
||||||
end
|
|
||||||
local ok, ret = pcall(f, ...)
|
local ok, ret = pcall(f, ...)
|
||||||
debug.sethook() -- Clear hook
|
debug.sethook() -- Clear hook
|
||||||
if not ok then error(ret, 0) end
|
if not ok then error(ret, 0) end
|
||||||
@ -432,9 +421,6 @@ local function run(pos, event)
|
|||||||
local mem = load_memory(meta)
|
local mem = load_memory(meta)
|
||||||
local code = meta:get_string("code")
|
local code = meta:get_string("code")
|
||||||
|
|
||||||
local err = code_prohibited(code)
|
|
||||||
if err then return err end
|
|
||||||
|
|
||||||
-- Create environment
|
-- Create environment
|
||||||
local env = create_environment(pos, mem, event)
|
local env = create_environment(pos, mem, event)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user