Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

many: make per-snap mount namespace MS_SHARED #6891

Closed
wants to merge 11 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 12 additions & 4 deletions cmd/snap-confine/mount-support.c
Expand Up @@ -241,11 +241,14 @@ static void sc_bootstrap_mount_namespace(const struct sc_mount_config *config)
// replicate the state of the root filesystem into the scratch directory.
sc_do_mount(config->rootfs_dir, scratch_dir, NULL, MS_REC | MS_BIND,
NULL);
// Make the scratch directory recursively private. Nothing done there will
// be shared with any peer group, This effectively detaches us from the
// original namespace and coupled with pivot_root below serves as the
// foundation of the mount sandbox.
// Make the scratch directory recursively slave. Nothing done there will be
// shared with the initial mount namespace. This effectively detaches us,
// in one way, from the original namespace and coupled with pivot_root
// below serves as the foundation of the mount sandbox. Following that,
// make it recursively shared so that changes performed in the per-snap
// mount namespace migrate to per-user mount namespaces.
sc_do_mount("none", scratch_dir, NULL, MS_REC | MS_SLAVE, NULL);
sc_do_mount("none", scratch_dir, NULL, MS_REC | MS_SHARED, NULL);
// Bind mount certain directories from the host filesystem to the scratch
// directory. By default mount events will propagate in both into and out
// of the peer group. This way the running application can alter any global
Expand Down Expand Up @@ -276,6 +279,7 @@ static void sc_bootstrap_mount_namespace(const struct sc_mount_config *config)
// from that of its own snap.
sc_do_mount("none", dst, NULL, MS_REC | MS_SLAVE, NULL);
}
sc_do_mount("none", dst, NULL, MS_REC | MS_SHARED, NULL);
if (mnt->altpath == NULL) {
continue;
}
Expand All @@ -294,6 +298,7 @@ static void sc_bootstrap_mount_namespace(const struct sc_mount_config *config)
if (!mnt->is_bidirectional) {
sc_do_mount("none", dst, NULL, MS_REC | MS_SLAVE, NULL);
}
sc_do_mount("none", dst, NULL, MS_REC | MS_SHARED, NULL);
}
if (config->normal_mode) {
// Since we mounted /etc from the host filesystem to the scratch directory,
Expand Down Expand Up @@ -401,6 +406,7 @@ static void sc_bootstrap_mount_namespace(const struct sc_mount_config *config)

sc_do_mount(src, dst, NULL, MS_BIND | MS_RDONLY, NULL);
sc_do_mount("none", dst, NULL, MS_SLAVE, NULL);
sc_do_mount("none", dst, NULL, MS_SHARED, NULL);
}
// Bind mount the directory where all snaps are mounted. The location of
// the this directory on the host filesystem may not match the location in
Expand All @@ -410,6 +416,7 @@ static void sc_bootstrap_mount_namespace(const struct sc_mount_config *config)
sc_must_snprintf(dst, sizeof dst, "%s/snap", scratch_dir);
sc_do_mount(SNAP_MOUNT_DIR, dst, NULL, MS_BIND | MS_REC, NULL);
sc_do_mount("none", dst, NULL, MS_REC | MS_SLAVE, NULL);
sc_do_mount("none", dst, NULL, MS_REC | MS_SHARED, NULL);
// Create the hostfs directory if one is missing. This directory is a part
// of packaging now so perhaps this code can be removed later.
if (access(SC_HOSTFS_DIR, F_OK) != 0) {
Expand Down Expand Up @@ -492,6 +499,7 @@ static void sc_bootstrap_mount_namespace(const struct sc_mount_config *config)
// performed in this mount namespace will not propagate to the peer group.
// This is another essential part of the confinement system.
sc_do_mount("none", SC_HOSTFS_DIR, NULL, MS_REC | MS_SLAVE, NULL);
sc_do_mount("none", SC_HOSTFS_DIR, NULL, MS_REC | MS_SHARED, NULL);
// Detach the redundant hostfs version of sysfs since it shows up in the
// mount table and software inspecting the mount table may become confused
// (eg, docker and LP:# 162601).
Expand Down
84 changes: 57 additions & 27 deletions cmd/snap-confine/snap-confine.apparmor.in
Expand Up @@ -133,89 +133,115 @@

# LP: #1668659
mount options=(rw rbind) /snap/ -> /snap/,
mount options=(rw rshared) -> /snap/,
mount options=(rw rslave) -> /snap/,
mount options=(rw rshared) -> /snap/,

# boostrapping the mount namespace
mount options=(rw rshared) -> /,
mount options=(rw bind) /tmp/snap.rootfs_*/ -> /tmp/snap.rootfs_*/,
mount options=(rw unbindable) -> /tmp/snap.rootfs_*/,
# the next line is for classic system
mount options=(rw unbindable) -> /tmp/snap.rootfs_*/,
# the next lines are for classic system
mount options=(rw rbind) @SNAP_MOUNT_DIR@/*/*/ -> /tmp/snap.rootfs_*/,
# the next line is for core system
mount options=(rw rbind) / -> /tmp/snap.rootfs_*/,
mount options=(rw rslave) -> @SNAP_MOUNT_DIR@/*/*/,
mount options=(rw rshared) -> @SNAP_MOUNT_DIR@/*/*/,
# the next lines are for core system
# all of the constructed rootfs is a rslave
mount options=(rw rslave) -> /tmp/snap.rootfs_*/,
# then it becomes shared for per-user mount namespaces
mount options=(rw rbind) / -> /tmp/snap.rootfs_*/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/,
mount options=(rw rshared) -> /tmp/snap.rootfs_*/,
# bidirectional mounts (for both classic and core)
# NOTE: this doesn't capture the MERGED_USR configuration option so that
# when a distro with merged /usr and / that uses apparmor shows up it
# should be handled here.
/{,run/}media/ w,
mount options=(rw rbind) /{,run/}media/ -> /tmp/snap.rootfs_*/{,run/}media/,
mount options=(rshared) -> /tmp/snap.rootfs_*/{,run/}media/,
/run/netns/ w,
mount options=(rw rbind) /run/netns/ -> /tmp/snap.rootfs_*/run/netns/,
mount options=(rshared) -> /tmp/snap.rootfs_*/run/netns/,
# unidirectional mounts (only for classic system)
mount options=(rw rbind) /dev/ -> /tmp/snap.rootfs_*/dev/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/dev/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/dev/,
mount options=(rw rshared) -> /tmp/snap.rootfs_*/dev/,

mount options=(rw rbind) /etc/ -> /tmp/snap.rootfs_*/etc/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/etc/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/etc/,
mount options=(rw rshared) -> /tmp/snap.rootfs_*/etc/,

mount options=(rw rbind) /home/ -> /tmp/snap.rootfs_*/home/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/home/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/home/,
mount options=(rw rshared) -> /tmp/snap.rootfs_*/home/,

mount options=(rw rbind) /root/ -> /tmp/snap.rootfs_*/root/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/root/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/root/,
mount options=(rw rshared) -> /tmp/snap.rootfs_*/root/,

mount options=(rw rbind) /proc/ -> /tmp/snap.rootfs_*/proc/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/proc/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/proc/,
mount options=(rw rshared) -> /tmp/snap.rootfs_*/proc/,

mount options=(rw rbind) /sys/ -> /tmp/snap.rootfs_*/sys/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/sys/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/sys/,
mount options=(rw rshared) -> /tmp/snap.rootfs_*/sys/,

mount options=(rw rbind) /tmp/ -> /tmp/snap.rootfs_*/tmp/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/tmp/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/tmp/,
mount options=(rw rshared) -> /tmp/snap.rootfs_*/tmp/,

mount options=(rw rbind) /var/lib/snapd/ -> /tmp/snap.rootfs_*/var/lib/snapd/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/var/lib/snapd/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/var/lib/snapd/,
mount options=(rw rshared) -> /tmp/snap.rootfs_*/var/lib/snapd/,

mount options=(rw rbind) /var/snap/ -> /tmp/snap.rootfs_*/var/snap/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/var/snap/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/var/snap/,
mount options=(rw rshared) -> /tmp/snap.rootfs_*/var/snap/,

mount options=(rw rbind) /var/tmp/ -> /tmp/snap.rootfs_*/var/tmp/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/var/tmp/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/var/tmp/,
mount options=(rw rshared) -> /tmp/snap.rootfs_*/var/tmp/,

mount options=(rw rbind) /run/ -> /tmp/snap.rootfs_*/run/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/run/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/run/,
mount options=(rw rshared) -> /tmp/snap.rootfs_*/run/,

mount options=(rw rbind) /var/lib/extrausers/ -> /tmp/snap.rootfs_*/var/lib/extrausers/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/var/lib/extrausers/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/var/lib/extrausers/,
mount options=(rw rshared) -> /tmp/snap.rootfs_*/var/lib/extrausers/,

mount options=(rw rbind) {,/usr}/lib{,32,64,x32}/modules/ -> /tmp/snap.rootfs_*{,/usr}/lib/modules/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*{,/usr}/lib/modules/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*{,/usr}/lib/modules/,
mount options=(rw rshared) -> /tmp/snap.rootfs_*{,/usr}/lib/modules/,

mount options=(rw rbind) {,/usr}/lib{,32,64,x32}/firmware/ -> /tmp/snap.rootfs_*{,/usr}/lib/firmware/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*{,/usr}/lib/firmware/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*{,/usr}/lib/firmware/,
mount options=(rw rshared) -> /tmp/snap.rootfs_*{,/usr}/lib/firmware/,

mount options=(rw rbind) /var/log/ -> /tmp/snap.rootfs_*/var/log/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/var/log/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/var/log/,
mount options=(rw rshared) -> /tmp/snap.rootfs_*/var/log/,

mount options=(rw rbind) /usr/src/ -> /tmp/snap.rootfs_*/usr/src/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/usr/src/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/usr/src/,
mount options=(rw rshared) -> /tmp/snap.rootfs_*/usr/src/,

mount options=(rw rbind) /mnt/ -> /tmp/snap.rootfs_*/mnt/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/mnt/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/mnt/,
mount options=(rw rshared) -> /tmp/snap.rootfs_*/mnt/,

# allow making host snap-exec available inside base snaps
mount options=(rw bind) @LIBEXECDIR@/ -> /tmp/snap.rootfs_*/usr/lib/snapd/,
mount options=(rw slave) -> /tmp/snap.rootfs_*/usr/lib/snapd/,
mount options=(rw slave) -> /tmp/snap.rootfs_*/usr/lib/snapd/,
mount options=(rw shared) -> /tmp/snap.rootfs_*/usr/lib/snapd/,

# allow making re-execed host snap-exec available inside base snaps
mount options=(ro bind) @SNAP_MOUNT_DIR@/core/*/usr/lib/snapd/ -> /tmp/snap.rootfs_*/usr/lib/snapd/,
# allow making snapd snap tools available inside base snaps
mount options=(ro bind) @SNAP_MOUNT_DIR@/snapd/*/usr/lib/snapd/ -> /tmp/snap.rootfs_*/usr/lib/snapd/,

# XXX: this seems unused
mount options=(rw bind) /usr/bin/snapctl -> /tmp/snap.rootfs_*/usr/bin/snapctl,
mount options=(rw slave) -> /tmp/snap.rootfs_*/usr/bin/snapctl,
mount options=(rw slave) -> /tmp/snap.rootfs_*/usr/bin/snapctl,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is unused, we should remove it, no?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I just didn't want to mix up other changes in this patch. I have a few cleanups for the profile in a separate patch.


# /etc/alternatives (classic)
mount options=(rw bind) @SNAP_MOUNT_DIR@/*/*/etc/alternatives/ -> /tmp/snap.rootfs_*/etc/alternatives/,
Expand All @@ -228,12 +254,16 @@
mount options=(rw slave) -> /tmp/snap.rootfs_*/etc/nsswitch.conf,
# the /snap directory
mount options=(rw rbind) @SNAP_MOUNT_DIR@/ -> /tmp/snap.rootfs_*/snap/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/snap/,
mount options=(rw rslave) -> /tmp/snap.rootfs_*/snap/,
mount options=(rw rshared) -> /tmp/snap.rootfs_*/snap/,
# pivot_root preparation and execution
mount options=(rw bind) /tmp/snap.rootfs_*/var/lib/snapd/hostfs/ -> /tmp/snap.rootfs_*/var/lib/snapd/hostfs/,
mount options=(rw private) -> /tmp/snap.rootfs_*/var/lib/snapd/hostfs/,
mount options=(rw private) -> /tmp/snap.rootfs_*/var/lib/snapd/hostfs/,
# pivot_root mediation in AppArmor is not complete. See LP: #1791711
pivot_root,
# post-pivot_root hostfs propagation change.
mount options=(rw rslave) -> /var/lib/snapd/hostfs/,
mount options=(rw rshared) -> /var/lib/snapd/hostfs/,
# cleanup
umount /var/lib/snapd/hostfs/tmp/snap.rootfs_*/,
umount /var/lib/snapd/hostfs/sys/,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes to the apparmor policy look fine.

Expand Down
12 changes: 11 additions & 1 deletion cmd/snap-update-ns/change.go
Expand Up @@ -330,10 +330,20 @@ func (c *Change) lowLevelPerform(as *Assumptions) error {
flags := umountNoFollow
if c.Entry.XSnapdDetach() {
flags |= syscall.MNT_DETACH
// If we are detaching something then before performing the actual detach
// switch the entire hierarchy to private event propagation (that is,
// none). This works around a bit of peculiar kernel behavior when the
// kernel reports EBUSY during a detach operation, because the changes
// propagate in a way that conflicts with itself. This is also documented
// in mount(2).
err = sysMount("none", c.Entry.Dir, "", syscall.MS_REC|syscall.MS_PRIVATE, "")
logger.Debugf("mount --make-rprivate %q (error: %v)", c.Entry.Dir, err)
}

// Perform the raw unmount operation.
err = sysUnmount(c.Entry.Dir, flags)
if err == nil {
err = sysUnmount(c.Entry.Dir, flags)
}
if err == nil {
as.AddChange(c)
}
Expand Down