summaryrefslogtreecommitdiff
path: root/lib/supple/sandbox.lua
blob: 6b2d3ab6f023a905d1251889f046afef29d55756 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
-- lib/supple/sandbox.lua
--
-- Sandbox (for) Untrusted Procedure Partitioning (in) Lua Engine
--
-- Code which runs the core sandbox functionality of supple.
--
-- This module runs in the sandbox interpreter which means some of the code
-- runs with root access.  As such, we minimise what can be done before
-- we drop privileges.
--
-- The wrapper used to run us already ensured that LUA_PATH etc are
-- not set, so we don't have to worry about non-system-installed modules
-- getting in our way.  Once the supple libraries are loaded (which will
-- include loading luxio etc) we're good to go and can ask the supple.capi
-- module to lock us down.
--
-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org>
--
-- For licence terms, see COPYING
--

local capi = require 'supple.capi'
local luxio = require 'luxio'
local sio = require 'luxio.simple'

local load = load
local setfenv = setfenv
local type = type

-- Run fn with globs as its globals.  Returns a function to run which
-- returns the return values of fn, and also wrap returns the table
-- which will be filled with any new globals fn creates.
--
-- If fn is a string then it is used as the source of the function, if it
-- is a function then it is expected to be a closure which when called 
-- repeatedly returns more data loaded (perhaps from a file?).  src is
-- expected to be the name associated with this source code.
--
-- In case of error, returns nil, errmsg
local function _wrap(fn, src, globs)
   local fn_glob = setmetatable({}, { __index = globs, __metatable=true })
   local fn_ret, msg

   assert(fn, "No function/source provided?")
   assert(src, "No source name provided?")
   globs = globs or {}

   if setfenv then
      -- Lua 5.1 style load...
      fn_ret, msg = ((type(fn) == "string") and loadstring or load)(fn, src)
      if not fn_ret then
	 return nil, msg
      end
      setfenv(fn_ret, fn_glob)
   else
      -- Lua 5.2 style load...
      fn_ret, msg = load(fn, src, "t", fn_glob)
      if not fn_ret then
	 return nil, msg
      end
   end

   assert(fn_ret, "Unusual, missing fn_ret now?")

   return fn_ret, fn_glob
end

local function sandboxed_go()
   -- Remove ourselves from the globals table so we cannot
   -- be reentered
   go = nil;

--   return io.receive()
   return 0
end

local function run()
   -- Run the sandbox
   local result, errno = capi.lockdown()

   if result ~= "ok"
-- START_TEST_ONLY
      and result ~= "oknonroot"
-- END_TEST_ONLY
   then
      -- Failure to sandbox, so abort
      print(result, luxio.strerror(errno))
      return errno
   end

-- START_TEST_ONLY
   if result ~= "oknonroot" then
-- END_TEST_ONLY
      -- Check that we're definitely solidly jailed
      fh, errno = sio.open("testfile", "rw")
      if fh then
	 fh:close()
	 luxio.unlink("testfile")
	 return 1
      end
-- START_TEST_ONLY
   end
-- END_TEST_ONLY
   
   -- Prepare a severely limited sandbox
   local sandbox_globals = {}

   for _, k in ipairs({ "table", "string", "pairs", "ipairs", "pcall",
			 "xpcall", "unpack", "tostring", "tonumber", "math",
			 "type", "coroutine", "select", "error", "assert" }) do
      sandbox_globals[k] = _G[k]
   end
   -- Complete its "globals"
   sandbox_globals._G = sandbox_globals
   -- And add in the magic function we need
   sandbox_globals.go = sandboxed_go

   local fn, globs = _wrap("return go()", "sandbox", sandbox_globals)
   if not fn then
      return 1
   end

   return fn()
end

return {
   run = run,
}