diff options
author | Andrew Leeming <andrew.leeming@codethink.co.uk> | 2016-10-14 12:28:55 +0100 |
---|---|---|
committer | Andrew Leeming <andrew.leeming@codethink.co.uk> | 2016-10-21 12:18:01 +0100 |
commit | ff7d57ba33c22ab2b20822a225dd7b1f3c991e85 (patch) | |
tree | 1647bc6775e8f3dd3a871d30776b8b5972af3bc7 | |
parent | efad18c41aea63c25826c7f0e0faa7644c3a9211 (diff) | |
download | sandboxlib-leeming/bwrap-rebase.tar.gz |
Bubblewrap is the default for executor_for_platform()leeming/bwrap-rebase
Previously executor_for_platform() would select linux-user-chroot
if availble. New behaviour is to look for bubblewrap first, then
linux-user-chroot, else falling back to chroot. To support this, a
generic 'get_program()' function was added to both bubblewrap.py
and linux_user_chroot.py for interfacing.
-rw-r--r-- | README.rst | 3 | ||||
-rw-r--r-- | sandboxlib/__init__.py | 28 | ||||
-rw-r--r-- | sandboxlib/bubblewrap.py | 30 | ||||
-rw-r--r-- | sandboxlib/linux_user_chroot.py | 3 |
4 files changed, 40 insertions, 24 deletions
@@ -35,18 +35,17 @@ Current backends - chroot: any POSIX OS, requires 'root' priviliges - linux-user-chroot_: Linux-only, does not require 'root', requires ``linux-user-chroot`` to be installed and setuid root +- bubblewrap: Does not require 'root', requires ``bwrap`` to be installed. Possible future backends ======================== -- Bubblewrap_ - Firejail_ - runC_ - `Security Enhanced Linux`_ (SELinux): see https://danwalsh.livejournal.com/28545.html - systemd-nspawn_ - Warden_ -.. _Bubblewrap: https://github.com/alexlarsson/bubblewrap .. _Firejail: https://github.com/netblue30/firejail/ .. _runC: http://runc.io/ .. _Security Enhanced Linux: http://selinuxproject.org/page/Main_Page diff --git a/sandboxlib/__init__.py b/sandboxlib/__init__.py index cdb2fb3..47aff9d 100644 --- a/sandboxlib/__init__.py +++ b/sandboxlib/__init__.py @@ -23,12 +23,14 @@ docstrings that describe the different parameters. import logging +import logging.config import os import platform import pipes import subprocess import warnings +logging.config.fileConfig(os.path.join(os.path.dirname(__file__), 'logger.conf')) class ProgramNotFound(Exception): pass @@ -170,13 +172,19 @@ def executor_for_platform(): "value %s." % backend_name) if backend is None and platform.uname()[0] == 'Linux': - log.info("Linux detected, looking for 'linux-user-chroot'.") - try: - program = sandboxlib.linux_user_chroot.linux_user_chroot_program() - log.info("Found %s, choosing 'linux_user_chroot' module.", program) - backend = sandboxlib.linux_user_chroot - except sandboxlib.ProgramNotFound as e: - log.debug("Did not find 'linux-user-chroot': %s", e) + # Not all backends may exist, so try them one by one in order of preference + prefered_backends = ['bubblewrap', 'linux-user-chroot'] + for backend_name in prefered_backends: + + log.info("Linux detected, looking for '{}'.".format(backend_name)) + try: + executor = get_executor(backend_name) + program = executor.get_program() + log.info("Found {}, choosing '{}' module.".format(program,backend_name)) + backend = executor + break + except sandboxlib.ProgramNotFound as e: + log.warn("Did not find '{}': {}".format(backend_name, e)) if backend is None: log.info("Choosing 'chroot' sandbox module.") @@ -187,7 +195,7 @@ def executor_for_platform(): def validate_extra_mounts(extra_mounts): '''Validate and fill in default values for 'extra_mounts' setting.''' - if extra_mounts == None: + if extra_mounts is None: return [] new_extra_mounts = [] @@ -220,7 +228,6 @@ def validate_extra_mounts(extra_mounts): return new_extra_mounts - def argv_to_string(argv): return ' '.join(map(pipes.quote, argv)) @@ -246,7 +253,8 @@ def _run_command(argv, stdout, stderr, cwd=None, env=None): dev_null = None log = logging.getLogger('sandboxlib') - log.debug('Running: {}'.format(argv)) + log.debug('Running: {} ENV: {}'.format(argv,env)) + log.debug(cwd) try: process = subprocess.Popen( diff --git a/sandboxlib/bubblewrap.py b/sandboxlib/bubblewrap.py index a0c005e..e03b7a0 100644 --- a/sandboxlib/bubblewrap.py +++ b/sandboxlib/bubblewrap.py @@ -124,14 +124,15 @@ def run_sandbox(command, cwd=None, env=None, bwrap_command += process_mounts(filesystem_root, extra_mounts, filesystem_writable_paths) - + # Set UID and GUI + bwrap_command.extend(['--unshare-user', '--uid', '0', '--gid', '0']) argv = bwrap_command + command - log.info("bubblewrap.run_command({}, stdou:{}, stderr:{}, env:{})" + log.info("bubblewrap.run_command({}, stdout:{}, stderr:{}, env:{})" .format(" ".join(argv), stdout, stderr, env)) - + exit, out, err = sandboxlib._run_command(argv, stdout, stderr, env=env) - + return exit, out, err @@ -149,6 +150,9 @@ def run_sandbox_with_redirection(command, **sandbox_config): # out and err will be None return exit +def get_program(): + return bubblewrap_program() + # Non API methods below @@ -204,12 +208,12 @@ def process_mounts(fs_root, mounts, writable_paths): log.debug("process_mounts(fs_root={}, mounts={}, writable_paths={})".format(fs_root, mounts, writable_paths)) extra_args = [] fs_dict = {} - + for ex_mnt in mounts: mnt_src, mnt_target, mnt_type, mnt_options = ex_mnt # TODO # How to handle options? Can bwrap do this? - + if mnt_target not in fs_dict.keys(): fs_dict[mnt_target] = {'src': mnt_src, 'type': mnt_type, 'options': mnt_options} # already exists. should only upgrade some things @@ -255,14 +259,16 @@ def process_mounts(fs_root, mounts, writable_paths): # First is using the --dev option that mounts host /dev # Second is using --dev-bind for moutning a [src] to [dest] # while allowing device access. - # - # How do we diferentiate the two? - # extra_args.extend(['--dev', mnt_target]) - # Experiment to see if --dev-bind fixes permissions errors - log.info("Using --dev-bind instead") - extra_args.extend(['--dev-bind', mnt_src, mnt_target]) + # How do we diferentiate the two? + # Check if we are mounting host root to target + if "/" in fs_dict.keys() and fs_dict['/']['src'] == "/": + log.info("Using --dev to share host dev") + extra_args.extend(['--dev', mnt_target]) + else: + log.info("Using --dev-bind for local dev") + extra_args.extend(['--dev-bind', mnt_src, mnt_target]) else: if is_mount_writable(mnt_target, writable_paths): extra_args.extend(['--bind', mnt_src, mnt_target]) diff --git a/sandboxlib/linux_user_chroot.py b/sandboxlib/linux_user_chroot.py index cab5344..f427b33 100644 --- a/sandboxlib/linux_user_chroot.py +++ b/sandboxlib/linux_user_chroot.py @@ -279,6 +279,9 @@ def create_mount_points_if_missing(filesystem_root, mount_info_list): os.makedirs(path) +def get_program(): + return linux_user_chroot_program() + def linux_user_chroot_program(): # Raises sandboxlib.ProgramNotFound if not found. return sandboxlib.utils.find_program('linux-user-chroot') |