Enable snap-confine namespace sharing #134

Closed
wants to merge 8 commits into
from
View
@@ -26,12 +26,18 @@ exclude:
- autom4te.cache
prepare: |
- echo "Spread is running as $(id)"
[ "${REUSE_PROJECT:-}" != 1 ] || exit 0
./spread-tests/spread-prepare.sh
suites:
spread-tests/main/:
summary: Full-system tests for snap-confine
+ restore-each: |
+ # NOTE: before snapd discards namespaces on snap removal
+ # we have to do it ourselves. All of the tests use one
+ # snap so this is easier to work with.
+ /usr/lib/snapd/snap-discard-ns snapd-hacker-toolbelt || :
spread-tests/regression/:
summary: Regression tests for past bug-fixes
+ restore-each: |
+ /usr/lib/snapd/snap-discard-ns snapd-hacker-toolbelt || :
View
@@ -453,21 +453,6 @@ static bool __attribute__ ((used))
return false;
}
-void sc_unshare_mount_ns()
-{
- // NOTE: unshare() and CLONE_NEWNS require linux >= 2.6.16 and glibc >=
- // 2.14 if using an older glibc, you'd need -D_BSD_SOURCE or
- // -D_SVID_SORUCE.
- if (unshare(CLONE_NEWNS) < 0) {
- die("unable to set up mount namespace");
- }
- // Make our "/" a rslave of the real "/". this means that mounts from the
- // host "/" get propagated to our namespace (i.e. we see new media mounts).
- if (mount("none", "/", NULL, MS_REC | MS_SLAVE, NULL) != 0) {
- die("can not make make / rslave");
- }
-}
-
void sc_populate_mount_ns(const char *security_tag)
{
// Get the current working directory before we start fiddling with
@@ -478,6 +463,11 @@ void sc_populate_mount_ns(const char *security_tag)
if (vanilla_cwd == NULL) {
die("cannot get the current working directory");
}
+ // Make our "/" a rslave of the real "/". this means that mounts from the
+ // host "/" get propagated to our namespace (i.e. we see new media mounts).
+ if (mount("none", "/", NULL, MS_REC | MS_SLAVE, NULL) != 0) {
+ die("can not make make / rslave");
+ }
// do the mounting if run on a non-native snappy system
if (is_running_on_classic_distribution()) {
setup_snappy_os_mounts();
View
@@ -18,20 +18,6 @@
#ifndef SNAP_MOUNT_SUPPORT_H
#define SNAP_MOUNT_SUPPORT_H
-/**
- * Unshare the mount namespace.
- *
- * Ensure we run in our own slave mount namespace, this will create a new mount
- * namespace and make it a slave of "/"
- *
- * Note that this means that no mount actions inside our namespace are
- * propagated to the main "/". We need this both for the private /tmp we create
- * and for the bind mounts we do on a classic distribution system.
- *
- * This also means you can't run an automount daemon under this launcher.
- **/
-void sc_unshare_mount_ns();
-
/**
* Assuming a new mountspace, populate it accordingly.
*
View
@@ -45,6 +45,14 @@
#include "mountinfo.h"
#include "cleanup-funcs.h"
+/*!
+ * The void directory.
+ *
+ * Snap confine moves to that directory in case it cannot retain the current
+ * working directory across the pivot_root call.
+ **/
+#define SC_VOID_DIR "/var/lib/snapd/void"
+
/**
* Directory where snap-confine keeps namespace files.
**/
@@ -267,6 +275,12 @@ void sc_create_or_join_ns_group(struct sc_ns_group *group)
die("cannot perform fstatfs() on an mount namespace file descriptor");
}
if (buf.f_type == NSFS_MAGIC) {
+ char *vanilla_cwd __attribute__ ((cleanup(sc_cleanup_string))) =
+ NULL;
+ vanilla_cwd = get_current_dir_name();
+ if (vanilla_cwd == NULL) {
+ die("cannot get the current working directory");
+ }
debug
("attempting to re-associate the mount namespace with the namespace group %s",
group->name);
@@ -276,6 +290,18 @@ void sc_create_or_join_ns_group(struct sc_ns_group *group)
debug
("successfully re-associated the mount namespace with the namespace group %s",
group->name);
+ // Try to re-locate back to vanilla working directory. This can fail
+ // because that directory is no longer present.
+ if (chdir(vanilla_cwd) != 0) {
+ debug
+ ("cannot remain in %s, moving to the void directory",
+ vanilla_cwd);
+ if (chdir(SC_VOID_DIR) != 0) {
+ die("cannot change directory to %s",
+ SC_VOID_DIR);
+ }
+ debug("successfully moved to %s", SC_VOID_DIR);
+ }
return;
}
debug("initializing new namespace group %s", group->name);
View
@@ -36,6 +36,7 @@
#include "udev-support.h"
#include "cleanup-funcs.h"
#include "user-support.h"
+#include "ns-support.h"
#include "quirks.h"
int sc_main(int argc, char **argv)
@@ -80,8 +81,21 @@ int sc_main(int argc, char **argv)
#endif // ifdef HAVE_SECCOMP
if (geteuid() == 0) {
- sc_unshare_mount_ns();
- sc_populate_mount_ns(security_tag);
+ const char *group_name = getenv("SNAP_NAME");
+ if (group_name == NULL) {
+ die("SNAP_NAME is not set");
+ }
+ sc_initialize_ns_groups();
+ struct sc_ns_group *group = NULL;
+ group = sc_open_ns_group(group_name);
+ sc_lock_ns_mutex(group);
+ sc_create_or_join_ns_group(group);
+ if (sc_should_populate_ns_group(group)) {
+ sc_populate_mount_ns(security_tag);
+ sc_preserve_populated_ns_group(group);
+ }
+ sc_unlock_ns_mutex(group);
+ sc_close_ns_group(group);
struct snappy_udev udev_s;
if (snappy_udev_init(security_tag, &udev_s) == 0)
setup_devices_cgroup(security_tag, &udev_s);
@@ -189,4 +189,70 @@
mount options=(rw rbind nodev nosuid noexec) /var/lib/snapd/hostfs/var/lib/lxd/ -> /var/lib/lxd/,
/var/lib/lxd/ w,
/var/lib/snapd/hostfs/var/lib/lxd r,
+
+ # support for the mount namespace sharing
+ mount options=(rw rbind) /run/snapd/ns/ -> /run/snapd/ns/,
+ mount options=(private) -> /run/snapd/ns/,
+ / rw,
+ /run/ rw,
+ /run/snapd/ rw,
+ /run/snapd/ns/ rw,
+ /run/snapd/ns/*.lock rwk,
+ /run/snapd/ns/*.mnt rw,
+ ptrace,
+ owner @{PROC}/*/mountinfo r,
+ capability sys_chroot,
+ capability sys_admin,
+ signal (send) set=("int") peer=@LIBEXECDIR@snap-confine//mount-namespace-capture-helper,
+
+ ^mount-namespace-capture-helper (attach_disconnected) {
+ # We run privileged, so be fanatical about what we include and don't use
+ # any abstractions
+ /etc/ld.so.cache r,
+ /lib/@{multiarch}/ld-*.so mr,
+ # libc, you are funny
+ /lib/@{multiarch}/libc{,-[0-9]*}.so* mr,
+ /lib/@{multiarch}/libpthread{,-[0-9]*}.so* mr,
+ /lib/@{multiarch}/librt{,-[0-9]*}.so* mr,
+ /lib/@{multiarch}/libgcc_s.so* mr,
+ # normal libs in order
+ /lib/@{multiarch}/libapparmor.so* mr,
+ /lib/@{multiarch}/libcgmanager.so* mr,
+ /lib/@{multiarch}/libnih.so* mr,
+ /lib/@{multiarch}/libnih-dbus.so* mr,
+ /lib/@{multiarch}/libdbus-1.so* mr,
+ /lib/@{multiarch}/libudev.so* mr,
+ /usr/lib/@{multiarch}/libseccomp.so* mr,
+ /lib/@{multiarch}/libseccomp.so* mr,
+
+ @LIBEXECDIR@/snap-confine r,
+
+ /dev/null rw,
+ /dev/full rw,
+ /dev/zero rw,
+ /dev/random r,
+ /dev/urandom r,
+
+ capability sys_ptrace,
+ capability sys_admin,
+ / r,
+ owner @{PROC}/ r,
+ owner @{PROC}/*/ r,
+ owner @{PROC}/*/ns/ r,
+ owner @{PROC}/*/ns/mnt r,
+ /run/ r,
+ /run/snapd/ r,
+ /run/snapd/ns/ r,
+ /run/snapd/ns/*.mnt rw,
+ # mount options=(rw bind) /proc/*/ns/mnt/ -> /run/snapd/ns/*.mnt/,
+ mount options=(rw bind) -> /run/snapd/ns/*.mnt,
+ signal (receive) peer=unconfined,
+ signal (receive) set=("int") peer=@LIBEXECDIR@snap-confine//mount-namespace-capture-helper,
+ signal (receive) set=("int") peer=@LIBEXECDIR@snap-confine,
+ ptrace (tracedby) peer=@LIBEXECDIR@/snap-confine,
+ ptrace,
+ }
+
+ # Allow snap-confine to be killed
+ signal (receive) peer=unconfined,
}