Largely functionally equivalent to chroot(1), but creates a new filesystem namespace so the chroot'd process can't escape. It's possible to do this with unshare/mount/chroot in a shell script, but it's a bit tricky to get right. Signed-off-by: Adam Jackson <ajax@xxxxxxxxxx> --- configure.ac | 24 ++++++++++ sys-utils/Makefile.am | 5 ++ sys-utils/chns.8 | 61 ++++++++++++++++++++++++++ sys-utils/chns.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 203 insertions(+), 0 deletions(-) create mode 100644 sys-utils/chns.8 create mode 100644 sys-utils/chns.c diff --git a/configure.ac b/configure.ac index 121ac50..8045bd3 100644 --- a/configure.ac +++ b/configure.ac @@ -741,6 +741,30 @@ fi AM_CONDITIONAL(BUILD_SWITCH_ROOT, test "x$build_switch_root" = xyes) +AC_ARG_ENABLE([chns], + AS_HELP_STRING([--disable-chns], [do not build chns]), + [], enable_chns=check +) +if test "x$enable_chns" = xno; then + build_chns=no +else + build_chns=yes + case $enable_chns:$linux_os in + yes:no) AC_MSG_ERROR([chns selected for non-linux system]);; + check:no) AC_MSG_WARN([non-linux system; do not build chns]) + build_chns=no;; + esac + if test "x$build_chns" = xyes; then + case $enable_chns:$have_unshare in + yes:no) AC_MSG_ERROR([chns selected but unshare() function not found]);; + check:no) AC_MSG_WARN([unshare() function not found; do not build chns]) + build_chns=no;; + esac + fi +fi +AM_CONDITIONAL(BUILD_CHNS, test "x$build_chns" = xyes) + + AC_ARG_ENABLE([pivot_root], AS_HELP_STRING([--disable-pivot_root], [do not build pivot_root]), [], enable_pivot_root=check diff --git a/sys-utils/Makefile.am b/sys-utils/Makefile.am index 76828cc..9578e3e 100644 --- a/sys-utils/Makefile.am +++ b/sys-utils/Makefile.am @@ -39,6 +39,11 @@ sbin_PROGRAMS += switch_root dist_man_MANS += switch_root.8 endif +if BUILD_CHNS +sbin_PROGRAMS += chns +dist_man_MANS += chns.8 +endif + if BUILD_UNSHARE usrbin_exec_PROGRAMS += unshare dist_man_MANS += unshare.1 diff --git a/sys-utils/chns.8 b/sys-utils/chns.8 new file mode 100644 index 0000000..c0bdb10 --- /dev/null +++ b/sys-utils/chns.8 @@ -0,0 +1,61 @@ +.\" Karel Zak <kzak@xxxxxxxxxx> +.TH CHNS 8 "APR 2010" "Linux" +.SH NAME +chns \- run a process in a new rooted namespace +.SH SYNOPSIS +.B chns +.RB [ \-hV ] +.LP +.B chns +.I newroot +.I init +.RI [ arg ...] +.SH DESCRIPTION +.B chns +starts the +.I init +process with the specifies arguments inside +.I newroot. +This is like the traditional +.B chroot +command, but +.B chns +creates a new filesystem namespace for the process. It is not possible to escape +the new root filesystem as it is with +.B chroot +nor do mount changes inside the new namespace appear in the parent (or vice versa). + +.SH OPTIONS +.IP "\fB\-h, \-\-help\fP" +show help and exit +.IP "\fB\-V, \-\-version\fP" +show version number and exit + +.SH RETURN VALUE +.B chns +returns 0 on success and 1 on failure. + +.SH NOTES +As with +.B chroot, +the calling process should ensure open directory file descriptors are not +inherited by the child process. Otherwise, the child can escape the root +with +.B fchdir(3). + +.SH "SEE ALSO" +.BR mount (8) +.BR chroot (2) +.BR init (8) +.BR switch_root (8) +.SH AUTHORS +.nf +.nf +Adam Jackson <ajax@xxxxxxxxxx> +Peter Jones <pjones@xxxxxxxxxx> +Jeremy Katz <katzj@xxxxxxxxxx> +Karel Zak <kzak@xxxxxxxxxx> +.fi +.SH AVAILABILITY +The chns command is part of the util-linux-ng package and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/. diff --git a/sys-utils/chns.c b/sys-utils/chns.c new file mode 100644 index 0000000..0825e53 --- /dev/null +++ b/sys-utils/chns.c @@ -0,0 +1,113 @@ +/* + * chns.c - like chroot(1), but with teeth. + * + * Copyright 2002-2009 Red Hat, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: + * Adam Jackson <ajax@xxxxxxxxxx> + * + * Based on switchroot.c, which was written by: + * Peter Jones <pjones@xxxxxxxxxx> + * Jeremy Katz <katzj@xxxxxxxxxx> + */ +#include <sys/mount.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <dirent.h> +#include <err.h> +#include <sched.h> + +#ifndef MS_MOVE +#define MS_MOVE 8192 +#endif + +static int chns(const char *newroot) +{ + if (chdir(newroot)) { + warn("failed to change directory to %s", newroot); + return -1; + } + + if (unshare(CLONE_NEWNS)) { + warn("failed to create mount namespace"); + return -1; + } + + if (mount(newroot, newroot, NULL, MS_BIND, NULL) < 0) { + warn("failed to bindmount %s", newroot); + return -1; + } + + if (mount(newroot, "/", NULL, MS_MOVE, NULL) < 0) { + warn("failed to mount moving %s to /", newroot); + return -1; + } + + if (chroot(newroot)) { + warn("failed to change root"); + return -1; + } + + return 0; +} + +static void usage(FILE *output) +{ + fprintf(output, "usage: %s <newrootdir> <program> <args>\n", + program_invocation_short_name); + exit(output == stderr ? EXIT_FAILURE : EXIT_SUCCESS); +} + +static void version(void) +{ + fprintf(stdout, "%s from %s\n", program_invocation_short_name, + PACKAGE_STRING); + exit(EXIT_SUCCESS); +} + +int main(int argc, char *argv[]) +{ + char *newroot, *init, **initargs; + + if (argv[1] && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) + usage(stdout); + if (argv[1] && (!strcmp(argv[1], "--version") || !strcmp(argv[1], "-V"))) + version(); + if (argc < 3) + usage(stderr); + + newroot = argv[1]; + init = argv[2]; + initargs = &argv[2]; + + if (!*newroot || !*init) + usage(stderr); + + if (chns(newroot)) + errx(EXIT_FAILURE, "failed. Sorry."); + + execv(init, initargs); + err(EXIT_FAILURE, "failed to execute %s", init); +} + -- 1.6.5.2 -- To unsubscribe from this list: send the line "unsubscribe util-linux-ng" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html