diff options
author | Sam Thursfield <sam.thursfield@codethink.co.uk> | 2015-05-22 16:22:13 +0100 |
---|---|---|
committer | Sam Thursfield <sam.thursfield@codethink.co.uk> | 2015-05-22 16:51:14 +0100 |
commit | 0d47774e17342170b0c756d64b4537752ab7ad8c (patch) | |
tree | 089ad81fb6a290d27f9696145204aeaf1fd20d1b | |
parent | 52995d06857e1631406c367ab68a8a9cdf05243a (diff) | |
download | sandboxlib-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-x | run-sandbox | 7 | ||||
-rw-r--r-- | sandboxlib/chroot.py | 22 | ||||
-rw-r--r-- | sandboxlib/linux_user_chroot.py | 35 |
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]) |