summaryrefslogtreecommitdiff
path: root/lib/supple/host.lua
blob: f0181faae461434d890faf87520f0a48678802e1 (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
-- lib/supple/host.lua
--
-- Sandbox (for) Untrusted Procedure Partitioning (in) Lua Engine
--
-- Management of the host side of Supple
--
-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org>
--
-- For licence terms, see COPYING
--

local luxio = require 'luxio'
local subprocess = require 'luxio.subprocess'

local comms = require 'supple.comms'
local objects = require 'supple.objects'

local hostname = "host"
local counter = 0

local function run_wrapper()
   local wrapperpath = "@@WRAPPER_BIN@@"
   -- START_TEST_SUPPLE
   wrapperpath = "./testwrapper"
   -- END_TEST_SUPPLE
   local fds = {}
   local ret, errno = luxio.socketpair(luxio.AF_UNIX, luxio.SOCK_STREAM,
				       luxio.PF_UNIX, fds)
   if ret ~= 0 then
      error("Unable to launch subprocess, could not prepare socketpair():"
	    .. luxio.strerror(errno))
   end
   local proc, msg = subprocess.spawn {
      "supple-sandbox",
      exe = wrapperpath,
      stdin = fds[1],
--      stdout = fds[1],
--      stderr = fds[1],
   }
   if not proc then
      error(msg)
   end
   luxio.close(fds[1])
   return proc, fds[2]
end

local function run_sandbox(codestr, codename, ...)
   -- Prepare and start a sandbox,
   -- compiling the codestr and running it
   -- with the given args
   local child, commsfd = run_wrapper()

   counter = counter + 1
   objects.set_name(("host[%d,%%d]"):format(counter))
   comms._set_fd(commsfd)
   objects.set_proc_call(comms.call)
   
   local func, err = comms.call("supple:loadstring", "__call", codestr, codename)
   if not func then
      error(err)
   end
   -- Clear 'err' because it'll be the environment table for the function
   -- which we do not need to fill out.
   err = nil

   -- In a protected manner, capture the output of the call
   local args, ret = {...}
   local function capture()
      ret = {func(unpack(args))}
   end
   local ok, err = pcall(capture)
   -- We need to clean up, so dump all the objects
   func = nil
   -- And ask the supple API to clear down too
   objects.clean_down(true)

   comms._set_fd(-1)
   luxio.kill(child.pid, luxio.SIGKILL)
   child:wait()
   if ok then
      return ok, unpack(ret)
   else
      return ok, err
   end
end

local function set_hostname(newname)
   hostname = newname
   counter = 0
end

return {
   run = run_sandbox,
   set_name = set_hostname,
}