Replace pivot_root implementation by LXC's #122

Closed
wants to merge 1 commit into
from
Jump to file or symbol
Failed to load files and symbols.
+38 −4
Split
View
@@ -26,6 +26,7 @@
#include <sys/types.h>
#include <sys/syscall.h>
#include <errno.h>
+#include <fcntl.h>
#include <sched.h>
#include <string.h>
#include <mntent.h>
@@ -276,14 +277,47 @@ void setup_snappy_os_mounts()
// moved all paths to /tmp/snap.rootfs_*. Because we are using unshare with
// CLONE_NEWNS we can essentially use pivot_root just like chroot but this
// makes apparmor unaware of the old root so everything works okay.
+
+ // The code below was copied and adapted from src/lxc/conf.c in
+ // github.com/lxc/lxc. It is available under the terms of the
+ // LGPLv2.1 and higher and was written by various LXC developers.
+
debug("chrooting into %s", rootfs_dir);
- if (chdir(rootfs_dir) == -1) {
- die("cannot change working directory to %s", rootfs_dir);
+
+ int oldroot = -1, newroot = -1;
@zyga

zyga Aug 31, 2016

Collaborator

I like to use __attribute__((cleanup(sc_cleanup_fd))) though I don't think it is strictly needed in this case.

@stgraber

stgraber Aug 31, 2016

Yeah and I think we very much want to be in control as to when we close those fds at the end as that's when the kernel will actually flush the old mount tree.

As for the error paths, well, we're about to exit, so closing the fds is a bit of a waste of time.

+ oldroot = open("/", O_DIRECTORY | O_PATH);
+ if (oldroot < 0) {
+ die("cannot open the root directory of the old filesystem");
+ }
+
+ newroot = open(rootfs_dir, O_DIRECTORY | O_PATH);
+ if (newroot < 0) {
+ die("cannot open the root directory of the new filesystem");
+ }
+
+ if (fchdir(newroot)) {
+ die("cannot switch to the root directory of the new filesystem");
}
- if (syscall(SYS_pivot_root, ".", rootfs_dir) == -1) {
+
+ if (syscall(SYS_pivot_root, ".", ".") == -1) {
die("cannot pivot_root to the new root filesystem");
}
- // Reset path as we cannot rely on the path from the host OS to
+
+ if (fchdir(oldroot) < 0) {
+ die("cannot switch to the root directory of the old filesystem");
+ }
+
+ if (umount2(".", MNT_DETACH) < 0) {
+ die("cannot unmount the old filesystem");
+ }
+
+ if (fchdir(newroot) < 0) {
+ die("cannot switch back to the root directory of the new filesystem");
+ }
+
+ close(oldroot);
+ close(newroot);
+
// make sense. The classic distribution may use any PATH that makes
// sense but we cannot assume it makes sense for the core snap
// layout. Note that the /usr/local directories are explicitly