summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Thursfield <sam.thursfield@codethink.co.uk>2015-06-09 12:21:26 +0100
committerSam Thursfield <sam.thursfield@codethink.co.uk>2015-06-09 12:21:26 +0100
commitccc25d0bee354f3b905e809cca10bb88d5e58b29 (patch)
treebe8e65a09a6f0083f876d5f7a03be3512ff267bb
parentb502a569b4f5c1b16b97b9813df1983c9e776a65 (diff)
downloadsandboxlib-ccc25d0bee354f3b905e809cca10bb88d5e58b29.tar.gz
Replace maximum_possible_isolation() with degrade_config_for_capabilities()
The goal is to be useful for apps which want to be flexible about which backend they use, taking into account that not all backends are capable of the same thing. My idea for degrade_config_for_capabilities() is that the app first defines the sandboxing config they would like to use, and then passes it through degrade_config_for_capabilities(). Any changes made are warned about, because probably the user needs to know if certain security features are being disabled. This commit also adds a CAPABILITIES dict to each backend.
-rw-r--r--sandboxlib/__init__.py30
-rw-r--r--sandboxlib/chroot.py44
-rw-r--r--sandboxlib/linux_user_chroot.py19
3 files changed, 51 insertions, 42 deletions
diff --git a/sandboxlib/__init__.py b/sandboxlib/__init__.py
index c568357..30cb71e 100644
--- a/sandboxlib/__init__.py
+++ b/sandboxlib/__init__.py
@@ -33,30 +33,18 @@ class ProgramNotFound(Exception):
pass
-def maximum_possible_isolation():
- '''Describe the 'tightest' isolation possible with a specific backend.
+def degrade_config_for_capabilities(in_config, warn=True):
+ '''Alter settings in 'in_config' that a given backend doesn't support.
- This function returns a dict, with the following keys:
+ This function is provided for users who want to be flexible about which
+ sandbox implementation they use, and who don't mind if not all of the
+ isolation that they requested is actually possible.
- - mounts
- - network
+ This is not a general purpose 'check your config' function. Any unexpected
+ keys or values in ``in_config`` will just be ignored.
- Each key maps to a parameter of the run_sandbox() function, and each
- value is a valid value for that parameter.
-
- Example result:
-
- {
- 'mounts': 'undefined'
- 'network': 'isolated'
- }
-
- You can pass the result directly to a run_sandbox() function directly,
- using the `**` operator to turn it into keyword arguments as in the
- following example:
-
- isolation_settings = maximum_possible_isolation()
- run_sandbox(root_path, ['echo', 'hello'], **isolation_settings)
+ If 'warn' is True, each change the function makes is logged using
+ warnings.warn().
'''
raise NotImplementedError()
diff --git a/sandboxlib/chroot.py b/sandboxlib/chroot.py
index 9f7b16a..e224ec0 100644
--- a/sandboxlib/chroot.py
+++ b/sandboxlib/chroot.py
@@ -24,10 +24,6 @@ syscall, which is likely to require 'root' priviliges.
If any 'extra_mounts' are specified, there must be a working 'mount' binary in
the host system.
-Supported mounts settings: 'undefined'.
-
-Supported network settings: 'undefined'.
-
The code would be simpler if we just used the 'chroot' program, but it's not
always practical to do that. First, it may not be installed. Second, we can't
set the working directory of the program inside the chroot, unless we assume
@@ -46,17 +42,41 @@ import warnings
import sandboxlib
-def maximum_possible_isolation():
- return {
- 'mounts': 'undefined',
- 'network': 'undefined',
- }
+CAPABILITIES = {
+ 'network': ['undefined'],
+ 'mounts': ['undefined'],
+ 'writable_paths': ['all'],
+}
-def process_mount_config(mounts, extra_mounts):
- supported_values = ['undefined', 'isolated']
+def degrade_config_for_capabilities(in_config, warn=True):
+ # Currently this is all done manually... it may make sense to add something
+ # in utils.py that automatically checks the config against CAPABILITIES.
+ out_config = in_config.copy()
+ backend = 'chroot'
+
+ def degrade_and_warn(name, allowed_value):
+ out_config[name] = allowed_value
+ if warn:
+ msg = (
+ 'Unable to set %(name)s=%(value)s in a %(backend)s sandbox, '
+ 'falling back to %(name)s=%(allowed_value)s'.format(locals()))
+ warnings.warn(msg)
+
+ if out_config.get('mounts', 'undefined') != 'undefined':
+ degrade_and_warn('mounts', 'undefined')
- assert mounts in supported_values, \
+ if out_config.get('network', 'undefined') != 'undefined':
+ degrade_and_warn('network', 'undefined')
+
+ if out_config.get('filesystem_writable_paths', 'all') != 'all':
+ degrade_and_warn('network', 'all')
+
+ return out_config
+
+
+def process_mount_config(mounts, extra_mounts):
+ assert mounts == 'undefined', \
"'%s' is an unsupported value for 'mounts' in the 'chroot' " \
"Mount sharing cannot be configured in this backend." % mounts
diff --git a/sandboxlib/linux_user_chroot.py b/sandboxlib/linux_user_chroot.py
index 3397a1a..755e70e 100644
--- a/sandboxlib/linux_user_chroot.py
+++ b/sandboxlib/linux_user_chroot.py
@@ -27,10 +27,6 @@ implementation here also uses 'unshare --mount', which can only be run as
linux-user-chroot to handle creating the new mount namespace and processing
any extra mounts would be a useful fix.
-Supported mounts settings: 'undefined', 'isolated'.
-
-Supported network settings: 'undefined', 'isolated'.
-
Much of this code is adapted from Morph, from the Baserock project, from code
written by Joe Burmeister, Richard Maw, Lars Wirzenius and others.
@@ -45,11 +41,16 @@ import tempfile
import sandboxlib
-def maximum_possible_isolation():
- return {
- 'mounts': 'isolated',
- 'network': 'isolated',
- }
+CAPABILITIES = {
+ 'network': ['isolated', 'undefined'],
+ 'mounts': ['isolated', 'undefined'],
+ 'writable_paths': ['all', 'any'],
+}
+
+
+def degrade_config_for_capabilities(in_config, warn=True):
+ # This backend has the most features, right now!
+ return in_config
def tmpfs_for_user():