Skip to content
This repository has been archived by the owner on Apr 15, 2020. It is now read-only.

Commit

Permalink
startup: pivot into a mostly-empty new root
Browse files Browse the repository at this point in the history
And umount everything but /proc and /run/cgmanager/fs in our new root.

That prevents us from pinning them if the host wants to unmount them.

Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
  • Loading branch information
hallyn committed Feb 11, 2015
1 parent 2eddc60 commit a08d1c0
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 2 deletions.
2 changes: 2 additions & 0 deletions configure.ac
Expand Up @@ -25,6 +25,8 @@ AC_PROG_CC_C99

AC_PATH_PROG([NIH_DBUS_TOOL], [nih-dbus-tool])

AC_CHECK_FUNCS([setns pivot_root])

PKG_CHECK_MODULES([NIH], [libnih >= 1.0.3])
PKG_CHECK_MODULES([NIH_DBUS], [libnih-dbus >= 1.0.0])
PKG_CHECK_MODULES([DBUS], [dbus-1 >= 1.2.16])
Expand Down
141 changes: 139 additions & 2 deletions fs.c
Expand Up @@ -56,6 +56,21 @@
#define AGENT SBINDIR "/cgm-release-agent"
#define AGENT_LINK_PATH "/run/cgmanager/agents"

/* Define pivot_root() if missing from the C library */
#ifndef HAVE_PIVOT_ROOT
static int pivot_root(const char * new_root, const char * put_old)
{
#ifdef __NR_pivot_root
return syscall(__NR_pivot_root, new_root, put_old);
#else
errno = ENOSYS;
return -1;
#endif
}
#else
extern int pivot_root(const char * new_root, const char * put_old);
#endif

char *all_controllers;

struct controller_mounts {
Expand Down Expand Up @@ -125,6 +140,10 @@ bool setup_base_run_path(void)
nih_fatal("%s: failed to create /run/cgmanager/fs", __func__);
return false;
}
if (mount("cgmfs", "/run/cgmanager/fs", "tmpfs", 0, "size=100000,mode=0755") < 0) {
nih_fatal("%s: failed to mount tmpfs onto /run/cgmanager/fs", __func__);
return false;
}
if (mkdir(AGENT_LINK_PATH, 0755) < 0 && errno != EEXIST) {
nih_fatal("%s: failed to create %s", __func__, AGENT_LINK_PATH);
return false;
Expand Down Expand Up @@ -806,6 +825,116 @@ int collect_subsystems(char *extra_mounts, char *skip_mounts)
return 0;
}

#define NEWROOT "/run/cgmanager/root"

static int do_pivot(void) {
int oldroot = -1, newroot = -1;

oldroot = open("/", O_DIRECTORY | O_RDONLY);
if (oldroot < 0) {
nih_fatal("%s: Error opening old-/ for fchdir", __func__);
return -1;
}
newroot = open(NEWROOT, O_DIRECTORY | O_RDONLY);
if (newroot < 0) {
nih_fatal("%s: Error opening new-/ for fchdir", __func__);
goto fail;
}

/* change into new root fs */
if (fchdir(newroot)) {
nih_fatal("%s: can't chdir to new rootfs '%s'", __func__, NEWROOT);
goto fail;
}

/* pivot_root into our new root fs */
if (pivot_root(".", ".")) {
nih_fatal("%s: pivot_root syscall failed: %s",
__func__, strerror(errno));
goto fail;
}

/*
* at this point the old-root is mounted on top of our new-root
* To unmounted it we must not be chdir'd into it, so escape back
* to old-root
*/
if (fchdir(oldroot) < 0) {
nih_fatal("%s: Error entering oldroot", __func__);
goto fail;
}
if (umount2(".", MNT_DETACH) < 0) {
nih_fatal("%s: Error detaching old root", __func__);
goto fail;
}

if (fchdir(newroot) < 0) {
nih_fatal("%s: Error re-entering newroot", __func__);
goto fail;
}

close(oldroot);
close(newroot);

return 0;

fail:
if (oldroot != -1)
close(oldroot);
if (newroot != -1)
close(newroot);
return -1;
}

static int pivot_into_new_root(void) {
int i, ret;
char *createdirs[] = {NEWROOT "/proc", NEWROOT "/run",
NEWROOT "/run/cgmanager", NEWROOT "/run/cgmanager/fs", NULL};
char path[100];

/* Mount tmpfs for new root */
if (mkdir(NEWROOT, 0755) < 0 && errno != EEXIST) {
nih_fatal("%s: Failed to create directory for new root\n", __func__);
return -1;
}
ret = mount("root", NEWROOT, "tmpfs", 0, "size=10000,mode=0755");
if (ret < 0) {
nih_fatal("%s: Failed to mount tmpfs for root", __func__);
return -1;
}

/* create /proc and /run/cgmanager/fs, and move-mount those */
for (i = 0; createdirs[i]; i++) {
if (mkdir(createdirs[i], 0755) < 0) {
nih_fatal("%s: failed to created %s\n", __func__, createdirs[i]);
return -1;
}
}

ret = snprintf(path, 100, NEWROOT "/proc");
if (ret < 0 || ret > 100)
return -1;
if (mount("/proc", path, NULL, MS_REC|MS_MOVE, 0) < 0) {
nih_fatal("%s: failed to move /proc into new root: %s",
__func__, strerror(errno));
return -1;
}
ret = snprintf(path, 100, NEWROOT "/run/cgmanager/fs");
if (ret < 0 || ret > 100)
return -1;
if (mount("/run/cgmanager/fs", path, NULL, MS_REC|MS_MOVE, 0) < 0) {
nih_fatal("%s: failed to move /run/cgmanager/fs into new root: %s",
__func__, strerror(errno));
return -1;
}

/* Pivot into new root */
if (do_pivot() < 0)
return -1;

return 0;
}

/**
* Mount the cgroup filesystems and record the information.
* This should take configuration data from /etc. For now,
Expand All @@ -827,8 +956,10 @@ int setup_cgroup_mounts(void)
return 0;
}

if (mount(NULL, "/", NULL, MS_REC|MS_SLAVE, 0) < 0)
nih_warn("Failed to re-mount / non-shared");
if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, 0) < 0) {
nih_warn("Failed to re-mount / private");
return -1;
}

/*
* Mount a tmpfs on top of /root in case / is still ro when we
Expand All @@ -847,6 +978,12 @@ int setup_cgroup_mounts(void)
}
}

/* Now pivot into a new root */
if (pivot_into_new_root() < 0) {
nih_fatal("Failed pivoting into new root");
return -1;
}

return 0;
}

Expand Down

0 comments on commit a08d1c0

Please sign in to comment.