summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Thursfield <sam.thursfield@codethink.co.uk>2015-05-22 16:22:13 +0100
committerSam Thursfield <sam.thursfield@codethink.co.uk>2015-05-22 16:51:14 +0100
commit0d47774e17342170b0c756d64b4537752ab7ad8c (patch)
tree089ad81fb6a290d27f9696145204aeaf1fd20d1b
parent52995d06857e1631406c367ab68a8a9cdf05243a (diff)
downloadsandboxlib-0d47774e17342170b0c756d64b4537752ab7ad8c.tar.gz
Add the ability to isolate the sandbox from the network, or not
Note that *sharing* the network is a different thing to *choosing not to isolate* the network. The former implies networking will actually work correctly, while the latter only implies that we didn't deliberately break it. So the default network behaviour is 'undefined'. The different backends have different capabilities, so I added a maximum_possible_isolation() method to return whatever is the most isolated configuration that a backend is capable of. I called this function maximum_security() initially, but it doesn't actually guarantee any kind of security at all so that wasn't a good name.
-rwxr-xr-xrun-sandbox7
-rw-r--r--sandboxlib/chroot.py22
-rw-r--r--sandboxlib/linux_user_chroot.py35
3 files changed, 61 insertions, 3 deletions
diff --git a/run-sandbox b/run-sandbox
index 2bea1d4..356d9f6 100755
--- a/run-sandbox
+++ b/run-sandbox
@@ -91,7 +91,12 @@ def run():
extra_env['AC_APP_NAME'] = manifest['name']
- executor.run_sandbox(rootfs_path, command, cwd=cwd, extra_env=extra_env)
+ sharing_config = executor.maximum_possible_isolation()
+
+ executor.run_sandbox(
+ rootfs_path, command, cwd=cwd, extra_env=extra_env,
+ **sharing_config)
+
else:
# We should at minimum handle filesystem trees as well.
raise RuntimeError(
diff --git a/sandboxlib/chroot.py b/sandboxlib/chroot.py
index 8495df1..7c79f5c 100644
--- a/sandboxlib/chroot.py
+++ b/sandboxlib/chroot.py
@@ -31,12 +31,32 @@ import sys
import sandboxlib
-def run_sandbox(rootfs_path, command, cwd=None, extra_env=None):
+def maximum_possible_isolation():
+ return {
+ 'network': 'undefined'
+ }
+
+
+def process_network_config(network):
+ # It'd be possible to implement network isolation on Linux using the
+ # clone() syscall. However, I prefer to have the 'chroot' backend behave
+ # the same on all platforms, and have separate Linux-specific backends to
+ # do Linux-specific stuff.
+
+ assert network == 'undefined', \
+ "'%s' is an unsupported value for 'network' in the 'chroot' backend. " \
+ "Network sharing cannot be be configured in this backend." % network
+
+
+def run_sandbox(rootfs_path, command, cwd=None, extra_env=None,
+ network='undefined'):
if type(command) == str:
command = [command]
env = sandboxlib.environment_vars(extra_env)
+ process_network_config(network)
+
pid = os.fork()
if pid == 0:
# Child process. It's a bit messy that we create a child process and
diff --git a/sandboxlib/linux_user_chroot.py b/sandboxlib/linux_user_chroot.py
index 7af7608..cbd15d3 100644
--- a/sandboxlib/linux_user_chroot.py
+++ b/sandboxlib/linux_user_chroot.py
@@ -21,7 +21,38 @@ import subprocess
import sandboxlib
-def run_sandbox(rootfs_path, command, cwd=None, extra_env=None):
+def maximum_possible_isolation():
+ return {
+ 'network': 'isolated',
+ }
+
+
+def process_network_config(network):
+ # Network isolation is pretty easy, we 'unshare' the network namespace, and
+ # nothing can access the network.
+
+ # Network 'sharing' is a lot harder to tie down: does it just mean 'not
+ # blocked'? Or does it mean 'working, with /etc/resolv.conf correctly set
+ # up'? So that's not handled yet.
+
+ supported_values = ['undefined', 'isolated']
+
+ assert network in supported_values, \
+ "'%s' is an unsupported value for 'network' in the " \
+ "'linux-user-chroot' backend. Supported values: %s" \
+ % (network, ', '.join(supported_values))
+
+ if network == 'isolated':
+ # This is all we need to do for network isolation
+ extra_linux_user_chroot_args = ['--unshare-net']
+ else:
+ extra_linux_user_chroot_args = []
+
+ return extra_linux_user_chroot_args
+
+
+def run_sandbox(rootfs_path, command, cwd=None, extra_env=None,
+ network='undefined'):
if type(command) == str:
command = [command]
@@ -29,6 +60,8 @@ def run_sandbox(rootfs_path, command, cwd=None, extra_env=None):
linux_user_chroot_args = []
+ linux_user_chroot_args += process_network_config(network)
+
if cwd is not None:
linux_user_chroot_args.extend(['--chdir', cwd])