Add a new Sandbox Lua module to the luaintf framework.
authorAntoine Cellerier <dionoea@videolan.org>
Sat, 8 Mar 2008 14:41:19 +0000 (15:41 +0100)
committerAntoine Cellerier <dionoea@videolan.org>
Sat, 8 Mar 2008 15:16:08 +0000 (16:16 +0100)
share/luaintf/modules/sandbox.lua [new file with mode: 0644]

diff --git a/share/luaintf/modules/sandbox.lua b/share/luaintf/modules/sandbox.lua
new file mode 100644 (file)
index 0000000..04d4762
--- /dev/null
@@ -0,0 +1,120 @@
+--[==========================================================================[\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