Skip to content

Commit

Permalink
Falling back to chroot(), if pivot_root() does not work
Browse files Browse the repository at this point in the history
  • Loading branch information
dmikushin committed Sep 12, 2023
1 parent f847c77 commit 2f373e2
Showing 1 changed file with 67 additions and 52 deletions.
119 changes: 67 additions & 52 deletions bubblewrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -3080,16 +3080,23 @@ main (int argc,

if (mkdir ("oldroot", 0755))
die_with_error ("Creating oldroot failed");
#if 0

#define ROOT_MODE_CHROOT 0
#define ROOT_MODE_PIVOT 1

int root_mode = ROOT_MODE_PIVOT;
if (pivot_root (base_path, "oldroot"))
die_with_error ("pivot_root");
#else
if (mount ("/", "oldroot", NULL, MS_SILENT | MS_MGC_VAL | MS_BIND | MS_REC, NULL) < 0)
die_with_error ("setting up newroot bind");
{
warn ("pivot_root() failed, falling back to chroot() with limitations");
root_mode = ROOT_MODE_CHROOT;

if (mount ("/", "oldroot", NULL, MS_SILENT | MS_MGC_VAL | MS_BIND | MS_REC, NULL) < 0)
die_with_error ("setting up newroot bind");

if (chroot (base_path))
die_with_error ("chroot");
}

if (chroot (base_path))
die_with_error ("chroot");
#endif
if (chdir ("/") != 0)
die_with_error ("chdir / (base path)");

Expand Down Expand Up @@ -3152,38 +3159,40 @@ main (int argc,

if (umount2 ("oldroot", MNT_DETACH))
die_with_error ("unmount old root");
#if 0

/* This is our second pivot. It's like we're a Silicon Valley startup flush
* with cash but short on ideas!
*
* We're aiming to make /newroot the real root, and get rid of /oldroot. To do
* that we need a temporary place to store it before we can unmount it.
*/
{ cleanup_fd int oldrootfd = open ("/", O_DIRECTORY | O_RDONLY);
if (oldrootfd < 0)
die_with_error ("can't open /");
if (chdir ("/newroot") != 0)
die_with_error ("chdir /newroot");
/* While the documentation claims that put_old must be underneath
* new_root, it is perfectly fine to use the same directory as the
* kernel checks only if old_root is accessible from new_root.
*
* Both runc and LXC are using this "alternative" method for
* setting up the root of the container:
*
* https://github.com/opencontainers/runc/blob/HEAD/libcontainer/rootfs_linux.go#L671
* https://github.com/lxc/lxc/blob/HEAD/src/lxc/conf.c#L1121
*/
if (pivot_root (".", ".") != 0)
die_with_error ("pivot_root(/newroot)");
if (fchdir (oldrootfd) < 0)
die_with_error ("fchdir to oldroot");
if (umount2 (".", MNT_DETACH) < 0)
die_with_error ("umount old root");
if (chdir ("/") != 0)
die_with_error ("chdir /");
}
#endif
if (root_mode == ROOT_MODE_PIVOT)
{
cleanup_fd int oldrootfd = open ("/", O_DIRECTORY | O_RDONLY);
if (oldrootfd < 0)
die_with_error ("can't open /");
if (chdir ("/newroot") != 0)
die_with_error ("chdir /newroot");
/* While the documentation claims that put_old must be underneath
* new_root, it is perfectly fine to use the same directory as the
* kernel checks only if old_root is accessible from new_root.
*
* Both runc and LXC are using this "alternative" method for
* setting up the root of the container:
*
* https://github.com/opencontainers/runc/blob/HEAD/libcontainer/rootfs_linux.go#L671
* https://github.com/lxc/lxc/blob/HEAD/src/lxc/conf.c#L1121
*/
if (pivot_root (".", ".") != 0)
die_with_error ("pivot_root(/newroot)");
if (fchdir (oldrootfd) < 0)
die_with_error ("fchdir to oldroot");
if (umount2 (".", MNT_DETACH) < 0)
die_with_error ("umount old root");
if (chdir ("/") != 0)
die_with_error ("chdir /");
}

if (opt_userns2_fd > 0 && setns (opt_userns2_fd, CLONE_NEWUSER) != 0)
die_with_error ("Setting userns2 failed");

Expand Down Expand Up @@ -3215,17 +3224,20 @@ main (int argc,
if (write_to_fd (sysctl_fd, "1", 1) < 0)
die_with_error ("sysctl user.max_user_namespaces = 1");
}
#if 0
if (unshare (CLONE_NEWUSER))
die_with_error ("unshare user ns");
#endif

if (root_mode == ROOT_MODE_PIVOT)
{
if (unshare (CLONE_NEWUSER))
die_with_error ("unshare user ns");
}

/* We're in a new user namespace, we got back the bounding set, clear it again */
drop_cap_bounding_set (FALSE);
#if 0
write_uid_gid_map (opt_sandbox_uid, ns_uid,
opt_sandbox_gid, ns_gid,
-1, FALSE, FALSE);
#endif

if (root_mode == ROOT_MODE_PIVOT)
write_uid_gid_map (opt_sandbox_uid, ns_uid,
opt_sandbox_gid, ns_gid,
-1, FALSE, FALSE);
}

if (opt_disable_userns || opt_assert_userns_disabled)
Expand All @@ -3236,15 +3248,18 @@ main (int argc,
if (res == 0)
die ("creation of new user namespaces was not disabled as requested");
}
#if 1
/* Now make /newroot the real root */
if (chdir ("/newroot") != 0)
die_with_error ("chdir newroot");
if (chroot ("/newroot") != 0)
die_with_error ("chroot /newroot");
if (chdir ("/") != 0)
die_with_error ("chdir /");
#endif

if (root_mode == ROOT_MODE_CHROOT)
{
/* Now make /newroot the real root */
if (chdir ("/newroot") != 0)
die_with_error ("chdir newroot");
if (chroot ("/newroot") != 0)
die_with_error ("chroot /newroot");
if (chdir ("/") != 0)
die_with_error ("chdir /");
}

/* All privileged ops are done now, so drop caps we don't need */
drop_privs (!is_privileged, TRUE);

Expand Down

0 comments on commit 2f373e2

Please sign in to comment.