Skip to content

Commit

Permalink
properly sandbox policy loader global env
Browse files Browse the repository at this point in the history
  • Loading branch information
mikz committed Feb 6, 2018
1 parent b4802de commit 0ef60e7
Showing 1 changed file with 74 additions and 17 deletions.
91 changes: 74 additions & 17 deletions gateway/src/apicast/policy_loader.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ local insert = table.insert
local setmetatable = setmetatable
local concat = table.concat

local _M = { }
local _G = _G
local _M = {}

local searchpath = package.searchpath
local root_loaded = package.loaded

local root_require = require
local pcall = pcall

local preload = package.preload

Expand Down Expand Up @@ -129,26 +129,83 @@ local function gen_require(package)
end
end

local function export(list, env)
assert(env, 'missing env')
list:gsub('%S+', function(id)
local module, method = id:match('([^%.]+)%.([^%.]+)')
if module then
env[module] = env[module] or {}
env[module][method] = _G[module][method]
else
env[id] = _G[id]
end
end)

return env
end

--- this is environment exposed to the policies
-- that means this is very light sandbox so policies don't mutate global env
-- and most importantly we replace the require function with our own
_M.env = {
math = math,
table = table,
string = string,
jit = jit,
pcall = pcall,
getfenv = getfenv, assert = assert, tonumber = tonumber, xpcall = xpcall,
select = select, rawset = rawset,
io = io, os = os, print = print, type = type,
setmetatable = setmetatable,
getmetatable = getmetatable,
coroutine = coroutine,
ipairs = ipairs, pairs = pairs, next = next,
ngx = ngx,
}
-- The env intentionally does not expose getfenv so sandboxed code can't get top level globals.
-- And also does not expose functions for loading code from filesystem (loadfile, dofile).
-- Neither exposes debug functions unless openresty was compiled --with-debug.
-- But it exposes ngx as the same object, so it can be changed from within the policy.
_M.env = export([[
_VERSION assert print xpcall pcall error
unpack next ipairs pairs select
collectgarbage gcinfo newproxy loadstring load
setmetatable getmetatable
tonumber tostring type
rawget rawequal rawlen rawset
bit.arshift bit.band bit.bnot bit.bor bit.bswap bit.bxor
bit.lshift bit.rol bit.ror bit.rshift bit.tobit bit.tohex
coroutine.create coroutine.resume coroutine.running coroutine.status
coroutine.wrap coroutine.yield coroutine.isyieldable
debug.traceback
io.open io.close io.flush io.tmpfile io.type
io.input io.output io.stderr io.stdin io.stdout
io.popen io.read io.lines io.write
math.abs math.acos math.asin math.atan math.atan2
math.ceil math.cos math.cosh math.deg math.exp math.floor
math.fmod math.frexp math.ldexp math.log math.pi
math.log10 math.max math.min math.modf math.pow
math.rad math.random math.randomseed math.huge
math.sin math.sinh math.sqrt math.tan math.tanh
os.clock os.date os.time os.difftime
os.execute os.getenv
os.rename os.tmpname os.remove
string.byte string.char string.dump string.find
string.format string.lower string.upper string.len
string.gmatch string.match string.gsub string.sub
string.rep string.reverse
table.concat table.foreach table.foreachi table.getn
table.insert table.maxn table.move table.pack
table.remove table.sort table.unpack
ngx
]], {})

_M.env._G = _M.env

-- add debug functions only when nginx was compiled --with-debug
if ngx.config.debug then
_M.env = export([[ debug.debug debug.getfenv debug.gethook debug.getinfo
debug.getlocal debug.getmetatable debug.getregistry
debug.getupvalue debug.getuservalue debug.setfenv
debug.sethook debug.setlocal debug.setmetatable
debug.setupvalue debug.setuservalue debug.upvalueid debug.upvaluejoin
]], _M.env)
end

local mt = {
__call = function(loader, ...) return loader.env.require(...) end
}
Expand Down

0 comments on commit 0ef60e7

Please sign in to comment.