--- /dev/null
+--[==========================================================================[\r
+ sandbox.lua: Lua sandboxing facilities\r
+--[==========================================================================[\r
+ Copyright (C) 2007 the VideoLAN team\r
+ $Id$\r
+\r
+ Authors: Antoine Cellerier <dionoea at videolan dot org>\r
+\r
+ This program is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.\r
+--]==========================================================================]\r
+\r
+module("sandbox",package.seeall)\r
+\r
+-- See Programming in Lua (second edition) for sandbox examples\r
+-- See http://lua-users.org/wiki/SandBoxes for a list of SAFE/UNSAFE variables\r
+\r
+local sandbox_blacklist = {\r
+ collectgarbage = true,\r
+ dofile = true,\r
+ _G = true,\r
+ getfenv = true,\r
+ getmetatable = true,\r
+ load = true, -- Can be protected I guess\r
+ loadfile = true, -- Can be protected I guess\r
+ loadstring = true, -- Can be protected I guess\r
+ rawequal = true,\r
+ rawget = true,\r
+ rawset = true,\r
+ setfenv = true,\r
+ setmetatable = true,\r
+ module = true,\r
+ require = true,\r
+ package = true,\r
+ debug = true,\r
+}\r
+\r
+function readonly_table_proxy(name,src,blacklist)\r
+ if type(src)=="nil" then return end\r
+ if type(src)~="table" then error("2nd argument must be a table (or nil)") end\r
+ local name = name\r
+ local t = src\r
+ local blist = {}\r
+ if blacklist then\r
+ for _, v in pairs(blacklist) do\r
+ blist[v] = true\r
+ end\r
+ end\r
+ local metatable_readonly = {\r
+ __index = function(self,key)\r
+ if blist[key] then\r
+ error("Sandbox: Access to `"..name.."."..key.."' is forbidden.")\r
+ end\r
+ return t[key]\r
+ end,\r
+ __newindex = function(self,key,value)\r
+ error("It is forbidden to modify elements of this table.")\r
+ end,\r
+ }\r
+ return setmetatable({},metatable_readonly)\r
+end\r
+\r
+-- Of course, all of this is useless if the sandbox calling code has\r
+-- another reference to one of these tables in his global environement.\r
+local sandbox_proxy = {\r
+ coroutine = readonly_table_proxy("coroutine",coroutine),\r
+ string = readonly_table_proxy("string",string,{"dump"}),\r
+ table = readonly_table_proxy("table",table),\r
+ math = readonly_table_proxy("math",math),\r
+ io = readonly_table_proxy("io",io),\r
+ os = readonly_table_proxy("os",os,{"exit","getenv","remove",\r
+ "rename","setlocale"}),\r
+ sandbox = readonly_table_proxy("sandbox",sandbox),\r
+}\r
+\r
+function sandbox(func,override)\r
+ local _G = getfenv(2)\r
+ local override = override or {}\r
+ local sandbox_metatable =\r
+ {\r
+ __index = function(self,key)\r
+ if override[key] then\r
+ return override[key]\r
+ end\r
+ if sandbox_blacklist[key] then\r
+ error( "Sandbox: Access to `"..key.."' is forbidden." )\r
+ end\r
+ --print(key,"not found in env. Looking in sandbox_proxy and _G")\r
+ local value = sandbox_proxy[key] or _G[key]\r
+ rawset(self,key,value) -- Keep a local copy\r
+ return value\r
+ end,\r
+ __newindex = function(self,key,value)\r
+ if override and override[key] then\r
+ error( "Sandbox: Variable `"..key.."' is read only." )\r
+ end\r
+ return rawset(self,key,value)\r
+ end,\r
+ }\r
+ local sandbox_env = setmetatable({},sandbox_metatable)\r
+ return function(...)\r
+ setfenv(func,sandbox_env)\r
+ local ret = {func(...)} -- Not perfect (if func returns nil before\r
+ -- another return value) ... but it's better\r
+ -- than nothing\r
+ setfenv(func,_G)\r
+ return unpack(ret)\r
+ end\r
+end
\ No newline at end of file