Re: [PATCH] chns: Like chroot, but effective.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux