summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Maw <richard.maw@codethink.co.uk>2018-09-04 14:37:54 +0100
committerTristan Van Berkom <tristan.van.berkom@gmail.com>2018-09-18 13:22:38 +0000
commitd042560842ce504bb57605b1388ccc7daaa16c66 (patch)
treee82ce765da3061b768e9bcd135df19f5f1d012aa
parent081dcafa03f1b2604ce52e9dc5be696444d8f71e (diff)
downloadbuildstream-d042560842ce504bb57605b1388ccc7daaa16c66.tar.gz
FUSE: Mount with -odev in chroot sandbox
This is needed to permit access to the device nodes added to /dev on Linux when FUSE is used as root. The chroot sandbox only works with all privileges, so there's no explicit check for being root or having the appropriate capabilities. A check for whether it's running as root isn't needed on Linux with bubblewrap because /dev or its devices are mounted on top of the FUSE layer, so device nodes are accessed directly rather than through the FUSE layer.
-rw-r--r--buildstream/_fuse/hardlinks.py3
-rw-r--r--buildstream/_fuse/mount.py6
-rw-r--r--buildstream/sandbox/_mount.py11
-rw-r--r--buildstream/sandbox/_sandboxchroot.py6
4 files changed, 18 insertions, 8 deletions
diff --git a/buildstream/_fuse/hardlinks.py b/buildstream/_fuse/hardlinks.py
index f9e2b959b..0797cb4bc 100644
--- a/buildstream/_fuse/hardlinks.py
+++ b/buildstream/_fuse/hardlinks.py
@@ -42,9 +42,10 @@ from .mount import Mount
#
class SafeHardlinks(Mount):
- def __init__(self, directory, tempdir):
+ def __init__(self, directory, tempdir, fuse_mount_options={}):
self.directory = directory
self.tempdir = tempdir
+ super().__init__(fuse_mount_options=fuse_mount_options)
def create_operations(self):
return SafeHardlinkOps(self.directory, self.tempdir)
diff --git a/buildstream/_fuse/mount.py b/buildstream/_fuse/mount.py
index 0ab1ce715..30cc85b77 100644
--- a/buildstream/_fuse/mount.py
+++ b/buildstream/_fuse/mount.py
@@ -87,6 +87,9 @@ class Mount():
# User Facing API #
################################################
+ def __init__(self, fuse_mount_options={}):
+ self._fuse_mount_options = fuse_mount_options
+
# mount():
#
# User facing API for mounting a fuse subclass implementation
@@ -184,7 +187,8 @@ class Mount():
# Run fuse in foreground in this child process, internally libfuse
# will handle SIGTERM and gracefully exit it's own little main loop.
#
- FUSE(self.__operations, self.__mountpoint, nothreads=True, foreground=True, nonempty=True)
+ FUSE(self.__operations, self.__mountpoint, nothreads=True, foreground=True, nonempty=True,
+ **self._fuse_mount_options)
# Explicit 0 exit code, if the operations crashed for some reason, the exit
# code will not be 0, and we want to know about it.
diff --git a/buildstream/sandbox/_mount.py b/buildstream/sandbox/_mount.py
index 49068fe92..4fca3d1b0 100644
--- a/buildstream/sandbox/_mount.py
+++ b/buildstream/sandbox/_mount.py
@@ -30,7 +30,7 @@ from .._fuse import SafeHardlinks
# Helper data object representing a single mount point in the mount map
#
class Mount():
- def __init__(self, sandbox, mount_point, safe_hardlinks):
+ def __init__(self, sandbox, mount_point, safe_hardlinks, fuse_mount_options={}):
scratch_directory = sandbox._get_scratch_directory()
# Getting _get_underlying_directory() here is acceptable as
# we're part of the sandbox code. This will fail if our
@@ -39,6 +39,7 @@ class Mount():
self.mount_point = mount_point
self.safe_hardlinks = safe_hardlinks
+ self._fuse_mount_options = fuse_mount_options
# FIXME: When the criteria for mounting something and it's parent
# mount is identical, then there is no need to mount an additional
@@ -82,7 +83,7 @@ class Mount():
@contextmanager
def mounted(self, sandbox):
if self.safe_hardlinks:
- mount = SafeHardlinks(self.mount_origin, self.mount_tempdir)
+ mount = SafeHardlinks(self.mount_origin, self.mount_tempdir, self._fuse_mount_options)
with mount.mounted(self.mount_source):
yield
else:
@@ -100,12 +101,12 @@ class Mount():
#
class MountMap():
- def __init__(self, sandbox, root_readonly):
+ def __init__(self, sandbox, root_readonly, fuse_mount_options={}):
# We will be doing the mounts in the order in which they were declared.
self.mounts = OrderedDict()
# We want safe hardlinks on rootfs whenever root is not readonly
- self.mounts['/'] = Mount(sandbox, '/', not root_readonly)
+ self.mounts['/'] = Mount(sandbox, '/', not root_readonly, fuse_mount_options)
for mark in sandbox._get_marked_directories():
directory = mark['directory']
@@ -113,7 +114,7 @@ class MountMap():
# We want safe hardlinks for any non-root directory where
# artifacts will be staged to
- self.mounts[directory] = Mount(sandbox, directory, artifact)
+ self.mounts[directory] = Mount(sandbox, directory, artifact, fuse_mount_options)
# get_mount_source()
#
diff --git a/buildstream/sandbox/_sandboxchroot.py b/buildstream/sandbox/_sandboxchroot.py
index 64fb3c1bc..b3a2a6d9d 100644
--- a/buildstream/sandbox/_sandboxchroot.py
+++ b/buildstream/sandbox/_sandboxchroot.py
@@ -35,6 +35,9 @@ from . import Sandbox, SandboxFlags
class SandboxChroot(Sandbox):
+
+ _FUSE_MOUNT_OPTIONS = {'dev': True}
+
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -67,7 +70,8 @@ class SandboxChroot(Sandbox):
# Create the mount map, this will tell us where
# each mount point needs to be mounted from and to
- self.mount_map = MountMap(self, flags & SandboxFlags.ROOT_READ_ONLY)
+ self.mount_map = MountMap(self, flags & SandboxFlags.ROOT_READ_ONLY,
+ self._FUSE_MOUNT_OPTIONS)
root_mount_source = self.mount_map.get_mount_source('/')
# Create a sysroot and run the command inside it