On Thu, Apr 08, 2010 at 02:09:37PM -0400, Adam Jackson wrote: > 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. Interesting idea. What about to add this functionality to the chroot(1)? For example add a new option "--ns" to move the process to a separate namespace with a real new root directory. I think coreutils already uses linux specific options for some utils, so a new option for chroot(1) should not be a problem. Jim, Pádraig -- any comment? > --- > 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)) { I think here should be: if (chroot(".")) > + 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); > +} > Karel -- Karel Zak <kzak@xxxxxxxxxx> http://karelzak.blogspot.com -- 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