From: Enrico Scholz Date: Tue, 30 Sep 2003 15:59:35 +0000 (+0000) Subject: initial checkin X-Git-Tag: VERSION_0_10~1344 X-Git-Url: http://git.linux-vserver.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b562f3d09686bb1686646c949b6f92c94eb2d64c;p=util-vserver.git initial checkin git-svn-id: http://svn.linux-vserver.org/svn/util-vserver/trunk@10 94cd875c-1c1d-0410-91d2-eb244daf1a30 --- diff --git a/util-vserver/lib/.cvsignore b/util-vserver/lib/.cvsignore new file mode 100644 index 0000000..ec96903 --- /dev/null +++ b/util-vserver/lib/.cvsignore @@ -0,0 +1,2 @@ +.deps +.dirstamp diff --git a/util-vserver/scripts/.cvsignore b/util-vserver/scripts/.cvsignore new file mode 100644 index 0000000..7f4fdef --- /dev/null +++ b/util-vserver/scripts/.cvsignore @@ -0,0 +1,2 @@ +.deps +util-vserver-vars diff --git a/util-vserver/scripts/functions b/util-vserver/scripts/functions new file mode 100644 index 0000000..959a2aa --- /dev/null +++ b/util-vserver/scripts/functions @@ -0,0 +1,216 @@ +# $Id$ --*- sh -*-- + +# Copyright (C) 2003 Enrico Scholz +# +# 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; version 2 of the License. +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +function findObject +{ + local mod=$1 + local var=$2 + local file= + local i=X + shift 2 + + for i; do + test "$i" || continue + test ! $mod "$i" || { file=$i; break; } + done + + test -z "$i" -o "$file" || { + echo "Can not find file for '$var'; aborting" + exit 1 + } >&2 + + eval "$var=\"$file\"" +} + +function findFile +{ + findObject -f "$@" +} + +function findDir +{ + findObject -d "$@" +} + +function getPhysicalDir +{ + ( set -P && cd "$1" && pwd ) +} + +function _pkgMountBindDir() +{ + test "$1" != "$2" || return 0 + + mount -n --bind "$1" "$2" +} + +function _pkgSetVarsBase +{ + case "$vserver" in + /*) + echo "not supported yet" + exit 1 + ;; + *) + BASEDIR=$CONFDIR/$vserver + test -d "$BASEDIR" || { + echo "Can not find configuration-directory" + exit 1 + } + + VDIR=$BASEDIR/vdir + test -d "$VDIR" || VDIR=/vservers/$vserver + VDIR=$(getPhysicalDir "$VDIR") + + PKGDIR=$BASEDIR/apps/pkgmgmt + test -d "$PKGDIR" || { + echo "Can not find configuration-directory for package-managment tools" + exit 1 + } + + findDir EXECDIR $PKGDIR/execdir / + + ;; + esac +} + +function _pkgSetVarsRPM +{ + case "$vserver" in + /*) + echo "not supported yet" + exit 1 + ;; + + *) + findDir RPMETCDIR $PKGDIR/rpmetc $PKGDIR/base/rpm/etc /etc/rpm + findDir RPMSTATEDIR $PKGDIR/rpmstate $PKGDIR/base/rpm/state + + findDir RPMLIBDIR $PKGDIR/rpmlib / + + RPMSTATEDIR=$(getPhysicalDir "$RPMSTATEDIR") + RPMETCDIR=$(getPhysicalDir "$RPMETCDIR") + ;; + esac +} + +function _pkgSetVarsApt +{ + case "$vserver" in + /*) + echo "not supported yet" + exit 1 + ;; + + *) + findDir APTETCDIR $PKGDIR/aptetc $PKGDIR/base/apt/etc /etc/apt + findDir APTSTATEDIR $PKGDIR/aptstate $PKGDIR/base/apt/state + findDir APTCACHEDIR $PKGDIR/aptcache $PKGDIR/base/apt/cache + findDir APTARCHIVDIR $PKGDIR/aptarchives $PKGDIR/base/apt/archives /var/cache/apt/archives + ;; + esac +} + +function _pkgMountBase +{ + : +} + +function _pkgMountApt +{ + : +} + +function _pkgMountRPM +{ + _pkgMountBindDir "$RPMETCDIR" /etc/rpm + test "$RPMLIBDIR" = "/" || _pkgMountBindDir "$RPMLIBDIR" /usr/lib/rpm + "$_SECURE_MOUNT" "$VDIR" "$RPMSTATEDIR" /var/lib/rpm +} + +function _pkgSetEnvBase +{ + test "$EXECDIR" = "/" || { + PATH=$EXECDIR:$PATH + LD_LIBRARY_PATH=$EXECDIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} + } + + export PATH LD_LIBRARY_PATH +} + +function _pkgSetEnvApt +{ + : +} + +function _pkgSetEnvRPM +{ + CUR_VSERVER=$vserver + RPM_FAKE_NAMESPACE_MOUNTS=/var/lib/rpm + RPM_BINARY=$_VRPM_PRELOAD + + export CUR_VSERVER RPM_FAKE_NAMESPACE_MOUNTS RPM_BINARY +} + +function pkgInit +{ + local i + local vserver=$1 + shift + + _pkgSetVarsBase + for i; do + case "$i" in + rpm) _pkgSetVarsRPM;; + apt) _pkgSetVarsApt;; + *) echo "Unknown packaging flavor"; exit 1;; + esac + done + + _pkgMountBase + for i; do + case "$i" in + rpm) _pkgMountRPM;; + apt) _pkgMountApt;; + esac + done + + _pkgSetEnvBase + for i; do + case "$i" in + rpm) _pkgSetEnvRPM;; + apt) _pkgSetEnvApt;; + esac + done + + _PKG_FLAVORS="$@" + _PKG_VSERVER=$vserver +} + +function getAllVservers +{ + local i + local var=$1 + + for i in $CONFDIR/*; do + test -d "$i" || continue + test ! -e "$i"/disabled || continue + test -d "$i"/vdir || continue + + eval "$var=\"$var ${i##$CONFDIR/}\"" + done +} diff --git a/util-vserver/scripts/vapt-get b/util-vserver/scripts/vapt-get new file mode 100755 index 0000000..0820003 --- /dev/null +++ b/util-vserver/scripts/vapt-get @@ -0,0 +1,73 @@ +#! /bin/bash + +# Copyright (C) 2003 Enrico Scholz +# +# 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; version 2 of the License. +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +: ${UTIL_VSERVER_VARS:=$(dirname $0)/util-vserver-vars} +test -e "$UTIL_VSERVER_VARS" || { + echo "Can not find util-vserver installation; aborting..." + exit 1 +} +. "$UTIL_VSERVER_VARS" +. "$_LIB_FUNCTIONS" + +function showHelp() +{ + echo "Usage: $0 * [--all] -- +" + exit $1 +} + +function showVersion() +{ + cat <&2 + +cnt=0 +res=255 +for i in $vservers; do + cnt=$[ cnt + 1 ] + _APT_GET=apt-get \ + "$_NEW_NAMESPACE" "$_VAPT_GET_WORKER" "$i" "$@" + res=$? +done + +test "$cnt" -ge 0 || echo "No vservers specified" >&2 +exit $res \ No newline at end of file diff --git a/util-vserver/scripts/vapt-get-worker b/util-vserver/scripts/vapt-get-worker new file mode 100755 index 0000000..260381e --- /dev/null +++ b/util-vserver/scripts/vapt-get-worker @@ -0,0 +1,53 @@ +#! /bin/bash -e +# $Id$ + +# Copyright (C) 2003 Enrico Scholz +# +# 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; version 2 of the License. +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +: ${UTIL_VSERVER_VARS:=$(dirname $0)/util-vserver-vars} +test -e "$UTIL_VSERVER_VARS" || { + echo "Can not find util-vserver installation; aborting..." + exit 1 +} +. "$UTIL_VSERVER_VARS" +. "$_LIB_FUNCTIONS" + + +function createAptFileSys() +{ + mkdir -p /var/state/apt/lists/partial + mkdir -p /var/cache/apt/archives/partial +} + +vserver="$1" +shift + +pkgInit "$vserver" rpm apt + +createAptFileSys + +$_APT_GET -o "RPM::RootDir=$VDIR" \ + -o "Dir=$VDIR" \ + -o "Dir::State=$APTSTATEDIR" \ + -o "Dir::Cache=$APTCACHEDIR" \ + -o "Dir::Cache::archives=$APTARCHIVDIR" \ + -o "Dir::Bin::rpm=$RPM_BINARY" \ + -o "Dir::Etc=$APTETCDIR" \ + -o "RPM::Order=true" \ + "$@" + +export PS1='@@ ' +exec bash diff --git a/util-vserver/scripts/vrpm-preload b/util-vserver/scripts/vrpm-preload new file mode 100755 index 0000000..50a5f5c --- /dev/null +++ b/util-vserver/scripts/vrpm-preload @@ -0,0 +1,55 @@ +#! /bin/bash -x + +: ${UTIL_VSERVER_VARS:=$(dirname $0)/util-vserver-vars} +test -e "$UTIL_VSERVER_VARS" || { + echo "Can not find util-vserver installation; aborting..." + exit 1 +} +. "$UTIL_VSERVER_VARS" + +lib=$_RPM_FAKE_SO + +function getSyscallParams +{ + set -- `grep '^__NR_new_s_context:' /proc/self/status` + scall_nr=$2 + test "$3" && scall_rev=${3##rev} +} + +need_cfg= +case "$CUR_VSERVER" in + /*) vdir=$CUR_VSERVER;; + *) vdir=$CONFDIR/$CUR_VSERVER/vdir + need_cfg=1;; +esac + +test "$CUR_VSERVER" -a -d "$vdir" || { + echo "No or invalid vserver-name given" + exit 1 +} + +ctxfile=/var/run/vservers/${CUR_VSERVER}.ctx +if test -f "$ctxfile"; then + . "$ctxfile" +else + S_CONTEXT= +fi + +for bin in `which rpm` /bin/rpm /usr/lib/rpm/rpmi ""; do + ldd "$bin" &>/dev/null && break +done + +test "$bin" || { + echo "No dynamically linked rpm binary found; exiting..." + exit 1 +} + + +getSyscallParams + +RPM_FAKE_S_CONTEXT_REV=$scall_rev \ +RPM_FAKE_S_CONTEXT_NR=$scall_nr \ +RPM_FAKE_CTX=$S_CONTEXT \ +RPM_FAKE_CAP=$[ ~0x3404040f ] \ +LD_PRELOAD=$lib${LD_PRELOAD:+:$LD_PRELOAD} \ +exec $bin "$@" diff --git a/util-vserver/scripts/vrpm-worker b/util-vserver/scripts/vrpm-worker new file mode 100755 index 0000000..85cfd28 --- /dev/null +++ b/util-vserver/scripts/vrpm-worker @@ -0,0 +1,34 @@ +#! /bin/bash -e +# $Id$ + +# Copyright (C) 2003 Enrico Scholz +# +# 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; version 2 of the License. +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +set -x + +: ${UTIL_VSERVER_VARS:=$(dirname $0)/util-vserver-vars} +test -e "$UTIL_VSERVER_VARS" || { + echo "Can not find util-vserver installation; aborting..." + exit 1 +} +. "$UTIL_VSERVER_VARS" +. "$_LIB_FUNCTIONS" + +vserver=$1 +shift + +pkgInit "$vserver" rpm + +exec $RPM_BINARY --root "$VDIR" "$@" \ No newline at end of file diff --git a/util-vserver/scripts/vserver-init b/util-vserver/scripts/vserver-init new file mode 100755 index 0000000..e3ad989 --- /dev/null +++ b/util-vserver/scripts/vserver-init @@ -0,0 +1,170 @@ +#! /bin/bash -e + +# Copyright (C) 2003 Enrico Scholz +# +# 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; version 2 of the License. +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +: ${UTIL_VSERVER_VARS:=$(dirname $0)/util-vserver-vars} +test -e "$UTIL_VSERVER_VARS" || { + echo "Can not find util-vserver installation; aborting..." + exit 1 +} +. "$UTIL_VSERVER_VARS" +. "$PKGLIBDIR/functions" + +tmp=$(getopt -o d:r: --long force,dir:,pkgcfg:,hostname:,iproot:,iprootmask:,iprootbcast:,iprootdev:,help,version \ + -n "$0" -- "$@") || exit 1 + +eval set -- "$tmp" + +distrib= +root=/vservers +dir= +name= +hostname= +iproot= +iprootmask= +iprootbcast= +iprootdev= +force= +pkgcfg= + + +function makeInode +{ + mknod -m$6 $1/$2 $3 $4 $5 +} + +function installBasePackages +{ + local name="$1" + local dir="$2" + + test "$dir" != / || return + for filelist in "$dir"/*; do + test -e "$filelist" || continue + local idx=0 + local can_fail=false + local flags= + + set -- $(<$filelist) + while test "$#" -gt 0; do + case "$1" in + --reinstall) flags='--reinstall';; + --can-fail) can_fail=true;; + *) break;; + esac + shift + done + "$_VAPT_GET" "$name" -- install $flags "$@" || $can_fail + done +} + +while true; do + case "$1" in + -d) distrib="$2"; shift 2;; + -r) root="$2"; shift 2;; + --pkgcfg) pkgcfg="$2"; shift 2;; + --force) force=1; shift;; + --dir) dir="$2"; shift 2;; + --hostname) hostname="$2"; shift 2;; + --iproot) iproot="$2"; shift 2;; + --iprootmask) iprootmask="$2"; shift 2;; + --iprootbcast) iprootbcast="$2"; shift 2;; + --iprootdev) iprootdev="$2"; shift 2;; + --help) showHelp; exit 0;; + --version) showVersion; exit 0;; + --) shift; break;; + *) echo "Internal error!"; exit 1;; + esac +done + +test "$#" != 0 || { + echo "No vserver name given" >&2 + exit 1 +} + +test "$#" = 1 || { + echo "Too much parameters" >&2 + exit 1 +} + +name=$1 +test "$dir" || dir=$name +test "$pkgcfg" || pkgcfg=$root/.pkg/$name + +vdir=$root/$dir +test ! -d "$vdir" || { + test "$force" && mv "$vdir" "$vdir".bak +} + +confdir="$CONFDIR/$name" +test ! -d "$confdir" || { + test "$force" && mv "$confdir" "$confdir".bak +} + +test ! -d "$vdir" -a ! -d "$confdir" || { + echo "vserver-topdirectory and/or configuration exist already; " + echo "please try to use '--force', or remove them manually" + exit 1 +} >&2 + +test "$distrib" || { + if test -e /etc/redhat-release; then + set -- $(cat /etc/redhat-release) + distrib=rh$5 + else + echo "Can not determine distribution; please specify it manually" + echo "with the '-d' option" + exit 1 + fi >&2 +} + +findFile INITPRE $CONFDIR/.distributions/$distrib/initpre $DISTRIBDIR/$distrib/initpre "" +findFile INITPOST $CONFDIR/.distributions/$distrib/initpost $DISTRIBDIR/$distrib/initpost "" +findFile DEVDESCR $CONFDIR/.distributions/$distrib/devs $DISTRIBDIR/$distrib/devs $DISTRIBDIR/defaults/devs +findDir APTTMPL $CONFDIR/.distributions/$distrib/apt $DISTRIBDIR/$distrib/apt +findDir RPMTMPL $CONFDIR/.distributions/$distrib/rpm $DISTRIBDIR/$distrib/rpm $DISTRIBDIR/defaults/rpm +findDir EXECDIR $CONFDIR/.distributions/$distrib/execdir $DISTRIBDIR/$distrib/execdir / +findDir RPMLIB $CONFDIR/.distributions/$distrib/rpmlib $DISTRIBDIR/$distrib/rpmlib / +findDir PKGDIR $CONFDIR/.distributions/$distrib/pkgs $DISTRIBDIR/$distrib/pkgs / + +mkdir -p "$confdir"/apps/pkgmgmt "$vdir"/{dev,/var/lib/rpm,/etc} \ + "$pkgcfg"/{rpm/{etc,state},apt/{etc,archives/partial,cache,state/lists/partial}} + +while read spec; do + makeInode "$vdir"/dev $spec +done <$DEVDESCR + +ln -s "$vdir" "$confdir"/vdir +for i in hostname iproot iprootmask iprootbcast iprootdev; do + i_=\$$i + eval "v=$i_" + test -z "$v" || echo $v >"$confdir/$i" +done + +ln -s "$pkgcfg" "$confdir/apps/pkgmgmt/base" +test "$EXECDIR" = / || ln -s "$EXECDIR" "$confdir/apps/pkgmgmt/execdir" +test "$RPMLIB" = / || ln -s "$RPMLIB" "$confdir/apps/pkgmgmt/rpmlib" + +cp -a "$RPMTMPL/"* "$pkgcfg/rpm/etc/" +cp -a "$APTTMPL/"* "$pkgcfg/apt/etc/" + + +test -z "$INITPRE" || "$INITPRE" "$name" +"$_VAPT_GET" "$name" -- update +installBasePackages "$name" "$PKGDIR" +"$_VAPT_GET" "$name" -- dist-upgrade +test -z "$INITPOST" || "$INITPOST" "$name" diff --git a/util-vserver/src/.cvsignore b/util-vserver/src/.cvsignore new file mode 100644 index 0000000..8b8bc7b --- /dev/null +++ b/util-vserver/src/.cvsignore @@ -0,0 +1,25 @@ +.deps +.dirstamp +capchroot +chbind +chcontext +fakerunlevel +filetime +ifspec +listdevip +new-namespace +parserpmdump +readlink +rebootmgr +reducecap +secure-mount +setctxlimit +showattr +showperm +vbuild +vcheck +vdu +vfiles +vreboot +vserver-stat +vunify diff --git a/util-vserver/src/new-namespace.c b/util-vserver/src/new-namespace.c new file mode 100644 index 0000000..5684f1e --- /dev/null +++ b/util-vserver/src/new-namespace.c @@ -0,0 +1,103 @@ +// $Id$ --*- c++ -*-- + +// Copyright (C) 2003 Enrico Scholz +// +// 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, 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, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +// Executes a program in a new namespace +// Based on http://www.win.tue.nl/~aeb/linux/lk/lk-6.html + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "util.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef CLONE_NEWNS +# define CLONE_NEWNS 0x00020000 +#endif + +static int +childFunc(void *argv_v) +{ + char ** argv = argv_v; + + execvp(argv[0], argv); + perror("execvp()"); + exit(255); +} + +static void +usage(int fd, char const *cmd, int exit_code) +{ + WRITE_MSG(fd, "Usage: "); + WRITE_STR(fd, cmd); + WRITE_MSG(fd, + " [--help] [--version] \n" + "\n" + "Executes in a new namespace.\n" + "\n" + "Report bugs to " PACKAGE_BUGREPORT "\n"); + + exit(exit_code); +} + +static void +showVersion() +{ + WRITE_MSG(1, + "new-namespace 0.1\n" + "Copyright (C) 2003 Enrico Scholz\n" + VERSION_COPYRIGHT_DISCLAIMER); + exit(0); +} + +int main(int argc, char *argv[]) +{ + char buf[128]; + int status; + pid_t pid, p; + + if (argc==1) usage(2, argv[0], 255); + if (!strcmp(argv[1], "--help")) usage(1, argv[0], 0); + if (!strcmp(argv[1], "--version")) showVersion(); + if (!strcmp(argv[1], "--")) ++argv; + + pid = clone(childFunc, buf+sizeof(buf)/2, CLONE_NEWNS|CLONE_VFORK|SIGCHLD, argv+1); + if (pid==-1) { + perror("clone()"); + exit(255); + } + + p = wait4(pid, &status, 0,0); + if (p==-1) { + perror("waitpid()"); + exit(255); + } + + if (WIFEXITED(status)) return WEXITSTATUS(status); + else return 255; +} diff --git a/util-vserver/src/rpm-fake.c b/util-vserver/src/rpm-fake.c new file mode 100644 index 0000000..ffd26ef --- /dev/null +++ b/util-vserver/src/rpm-fake.c @@ -0,0 +1,258 @@ +// $Id$ --*- c++ -*-- + +// Copyright (C) 2003 Enrico Scholz +// +// 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; version 2 of the License. +// +// 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, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LIBNAME "rpm-fake.so" +#define PLATFORM_FILE "/etc/rpm/platform" + +#define INIT(FILE,FUNC) FUNC##_func = dlsym(FILE, #FUNC) +#define DECLARE(FUNC) static __typeof__(FUNC) * FUNC##_func = 0 + +static bool is_initialized = false; +DECLARE(execv); + //DECLARE(open); + +static int def_NR_new_s_context = 259; +#undef __NR_new_s_context +static int __NR_new_s_context_rev0; +static int __NR_new_s_context_rev1; + +static int new_s_context_rev0(int, int, int); +static int new_s_context_rev1(int, int *, int, int); + +_syscall3(int, new_s_context_rev0, int, newctx, int, remove_cap, int, flags) +_syscall4(int, new_s_context_rev1, int, nbctx, int *, ctxs, int, remove_cap, int, flags) + +static int +new_s_context(int rev, + int nbctx, int *ctxs, int remove_cap, int flags) +{ + int ret; + + switch (rev) { + case 0 : + { + int ctx; + + switch (nbctx) { + case 0 : ctx = -1; break; + case 1 : ctx = ctxs[0]; break; + default : errno = EINVAL; return -1; + } + + ret = new_s_context_rev0(ctx, remove_cap, flags); + + break; + } + + case 1 : + ret = new_s_context_rev1(nbctx, ctxs, remove_cap, flags); + break; + + default : + errno = EINVAL; return -1; + } + + return ret; +} + +static void +initVserverSyscalls(int s_context_NR) +{ + int nr = (s_context_NR!=-1) ? s_context_NR : def_NR_new_s_context; + + __NR_new_s_context_rev0 = __NR_new_s_context_rev1 = nr; +} + +static int +getAndClearEnv(char const *key, int dflt) +{ + char *env = getenv(key); + int res; + + if (env==0 || env[0]=='\0') res = dflt; + else { + res = atoi(env); + unsetenv(key); + } + + return res; +} + +static void +initLib() +{ + if (is_initialized) return; + + initVserverSyscalls(getAndClearEnv("RPM_FAKE_S_CONTEXT_NR", -1)); + INIT(RTLD_NEXT, execv); + //INIT(RTLD_NEXT, open); + + is_initialized = true; +} + +static void +fixPreloadEnv() +{ + char *env = getenv("LD_PRELOAD"); + char *pos; + + // the const <-> non-const assignment is not an issue since the following modifying operations + // will not be executed in the const-case + env = env ? env : ""; + pos = strstr(env, LIBNAME); + + if (pos!=0) { + char *end_pos = pos + sizeof(LIBNAME); + bool is_end = (end_pos[-1]=='\0'); + char *start_pos; + + end_pos[-1] = '\0'; + start_pos = strrchr(env, ':'); + if (start_pos==0) start_pos = env; + else if (!is_end) ++start_pos; + + if (is_end) *start_pos = '\0'; + else memmove(start_pos, end_pos, strlen(end_pos)+1); + } + +#ifdef DEBUG + printf("env='%s'\n", env); +#endif + + if (*env=='\0') unsetenv("LD_PRELOAD"); +} + +static int +execvWorker(char const *path, char * const argv[]) +{ + int res; + int ctx; + + printf("+execvWorker\n"); + ctx = getAndClearEnv("RPM_FAKE_CTX", -1); + if ( (res=new_s_context(getAndClearEnv("RPM_FAKE_S_CONTEXT_REV", 0), + ctx==-1 ? 0 : 1, + &ctx, + getAndClearEnv("RPM_FAKE_CAP", ~0x3404040f), + getAndClearEnv("RPM_FAKE_FLAGS", 0)))!=-1 && + (res=execv_func(path, argv)!=-1) ) {} + printf("-execvWorker -> res=%u, err=%s\n",res,strerror(errno)); + + return res; +} + +struct ExecvParams +{ + char const * path; + char * const * argv; + char const * mnts; +}; + +static int +removeNamespaceMountsChild(void *params_v) +{ + struct ExecvParams * params = params_v; + char buf[strlen(params->mnts)+1], *ptr; + + strcpy(buf, params->mnts); + ptr = strtok(buf, ":"); + while (ptr) { + system("cat /proc/mounts"); + system("pstree -h"); + system("ls -l /proc/self/ /proc/self/fd/ /var/lib /var/lib/rpm/"); + if (umount2(ptr, 0)==-1) { dprintf(2, "ptr='%s' -> ", ptr); perror("umount2()"); return -1; } + ptr = strtok(0, ":"); + } + + unsetenv("RPM_FAKE_NAMESPACE_MOUNTS"); + return execvWorker(params->path, params->argv); +} + +static int +removeNamespaceMounts(char const *path, char * const argv[]) +{ + char const * mnts = getenv("RPM_FAKE_NAMESPACE_MOUNTS"); + + printf("mnts='%s'\n", mnts); + if (mnts==0) return execvWorker(path, argv); + + { + printf("l=%u\n", __LINE__); + char buf[512 + 2*strlen(mnts)]; + int status; + pid_t p; + struct ExecvParams params = { + .path = path, + .argv = argv, + .mnts = mnts, + }; + + printf("l=%u\n", __LINE__); + + + system("mount -t proc none /proc"); + system("cat /proc/mounts"); + //system("pstree -h"); + system("ls -l /proc/self/ /proc/self/fd/ /var/lib /var/lib/rpm/"); + pid_t pid = clone(removeNamespaceMountsChild, buf+sizeof(buf)/2, + CLONE_NEWNS|SIGCHLD|CLONE_VFORK, ¶ms); + + printf("l=%u\n", __LINE__); + if (pid==-1) return -1; + while ((p=waitpid(pid, &status, 0))==-1 && + (errno==EINTR || errno==EAGAIN)) ; + if (p==-1) return -1; + + printf("removeNamespaceMountsChild() -> status=%u\n", status); + + if (WIFEXITED(status)) exit(WEXITSTATUS(status)); + if (WIFSIGNALED(status)) kill(getpid(), WTERMSIG(status)); + + return -1; + } +} + +int +execv(char const *path, char * const argv[]) __THROW +{ + initLib(); + fixPreloadEnv(); + return removeNamespaceMounts(path, argv); +} diff --git a/util-vserver/src/secure-mount.c b/util-vserver/src/secure-mount.c new file mode 100644 index 0000000..194cc41 --- /dev/null +++ b/util-vserver/src/secure-mount.c @@ -0,0 +1,153 @@ +// $Id$ --*- c++ -*-- + +// Copyright (C) 2003 Enrico Scholz +// +// 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; version 2 of the License. +// +// 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, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + + // secure-mount + // + // mounts into the chroot at destination in a way + // that prevents symlink attacks + + // algorithm: + // enter chroot + // mount tmpfs-directory + // leave chroot + // mount --bind tmpfs + // enter chroot + // mount --move tmpfs + +#ifdef HAVE_CONFIG_H +# include +#endif + +#define VERSION_COPYRIGHT_YEAR "2003" +#define VERSION_COPYRIGHT_AUTHOR "Enrico Scholz" +#include "util.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define MNTPOINT "/etc" + +static void +showHelp(int fd, char const *cmd, int res) +{ + WRITE_MSG(fd, "Usage: "); + WRITE_STR(fd, cmd); + WRITE_MSG(fd, + " \n\n" + "Please report bugs to " PACKAGE_BUGREPORT "\n"); + + exit(res); +} + +static void +showVersion() +{ + WRITE_MSG(1, + "secure-mount 0.23.5\n" + "Copyright (C) 2003 Enrico Scholz\n" + VERSION_COPYRIGHT_DISCLAIMER); + exit(0); +} + +int main(int argc, char *argv[]) +{ + int fd = open("/", O_RDONLY); + // HACK: sanity checks should be done before declaration, but this does + // not work with C89 compilers + char path[strlen(argc==1 ? "" : argv[1]) + sizeof(MNTPOINT) + 3]; + + if (argc>=2) { + if (!strcmp(argv[1], "--help")) showHelp(1, argv[0], 0); + if (!strcmp(argv[1], "--version")) showVersion(); + } + if (argc!=4) { + WRITE_MSG(2, "Bad parameter count; use --help for further information.\n"); + exit(255); + } + + if (chroot(argv[1]) == -1 || + chdir("/") == -1) { + perror("chroot()/chdir()"); + exit(1); + } + + if (mount("none", MNTPOINT, "tmpfs", 0, "size=4k")==-1) { + perror("mount()"); + exit(1); + } + + if (mkdir(MNTPOINT "/x",0600) == -1) { + perror("mkdir()/fchdir()"); + goto err1; + } + + if (fchdir(fd) == -1 || + chroot(".") == -1) { + perror("chroot()"); + goto err2; + } + + strcpy(path, argv[1]); + strcat(path, MNTPOINT "/x"); + + if (mount(argv[2], path, "", MS_BIND, 0)==-1) { + perror("mount()"); + goto err3; + } + + if (chroot(argv[1]) == -1) { + perror("chroot()"); + goto err4; + } + + if (chdir("/") == -1 || + mount(MNTPOINT "/x", argv[3], "", MS_MOVE, 0) == -1) { + perror("chdir()/mount()"); + goto err5; + } + + if (umount(MNTPOINT) == -1) { + perror("umount()"); + } + + return 0; + + err5: + err4: + if (umount(path)==-1) perror("umount(path)"); + + err3: + if (chdir(argv[1])==-1) { + perror("chdir()"); + return 1; + } + + err2: + err1: + if (umount("mnt")==-1) perror("umount(\"mnt\")"); + + return 1; +} diff --git a/util-vserver/src/util.h b/util-vserver/src/util.h new file mode 100644 index 0000000..ebf6ee0 --- /dev/null +++ b/util-vserver/src/util.h @@ -0,0 +1,44 @@ +// $Id$ --*- c++ -*-- + +// Copyright (C) 2003 Enrico Scholz +// +// 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; version 2 of the License. +// +// 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, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +#ifndef H_UTIL_VSERVER_SRC_UTIL_H +#define H_UTIL_VSERVER_SRC_UTIL_H + +#include +#include + +#ifndef PACKAGE_BUGREPORT +# define PACKAGE_BUGREPORT "???" +#endif + +#ifndef VERSION_COPYRIGHT_DISCLAIMER +# define VERSION_COPYRIGHT_DISCLAIMER \ + "This program is free software; you may redistribute it under the terms of\n" \ + "the GNU General Public License. This program has absolutely no warranty.\n" +#endif + +inline static void +writeStr(int fd, char const *cmd) +{ + (void)write(fd, cmd, strlen(cmd)); +} + +#define WRITE_MSG(FD,X) (void)(write(FD,X,sizeof(X))) +#define WRITE_STR(FD,X) writeStr(FD,X) + +#endif // H_UTIL_VSERVER_SRC_UTIL_H diff --git a/util-vserver/sysv/.cvsignore b/util-vserver/sysv/.cvsignore new file mode 100644 index 0000000..80bab4b --- /dev/null +++ b/util-vserver/sysv/.cvsignore @@ -0,0 +1,10 @@ +rebootmgr +v_gated +v_httpd +v_named +v_portmap +v_sendmail +v_smb +v_sshd +v_xinetd +vservers diff --git a/util-vserver/tests/.cvsignore b/util-vserver/tests/.cvsignore new file mode 100644 index 0000000..0667ff3 --- /dev/null +++ b/util-vserver/tests/.cvsignore @@ -0,0 +1,8 @@ +.deps +.dirstamp +chrootsafe +escaperoot +forkbomb +testipc +testlimit +testopenf