[Devel] [PATCH v2 4/8] modify tar extraction to account for user namespace
Kir Kolyshkin
kir at openvz.org
Mon Apr 15 18:23:36 PDT 2013
On 03/22/2013 03:48 AM, Glauber Costa wrote:
> If we are running upstream with user namespaces, we need to create the
> container filesystem not with the ownership preserved, but reflecting the
> mapping we need to apply.
>
> The long term goal is to patch the tar utility to allow us to specify an offset
> that will be applied during extraction. However, even if tar is modified, the
> legacy base of old tar utilities is still too big. We can employ a trick to
> allow container creation right now, as well as to avoid compatibility problems:
> we will resort to LD_PRELOAD to load a schim that captures calls to the chown
> family of system calls and applies the offset manually.
looks fine to me now
> Signed-off-by: Glauber Costa <glommer at parallels.com>
> ---
> scripts/vps-create.in | 19 ++++++++++
> src/lib/Makefile.am | 3 ++
> src/lib/chown_preload.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++
> src/lib/create.c | 21 +++++++----
> vzctl.spec | 2 +-
> 5 files changed, 130 insertions(+), 8 deletions(-)
> create mode 100644 src/lib/chown_preload.c
>
> diff --git a/scripts/vps-create.in b/scripts/vps-create.in
> index 126f048..53f6643 100755
> --- a/scripts/vps-create.in
> +++ b/scripts/vps-create.in
> @@ -22,11 +22,27 @@
> # Required parameters:
> # VE_PRVT - path to root of CT private areas
> # PRIVATE_TEMPLATE - path to private template used as a source for copying
> +#
> +# Optional parameters:
> +# UID_OFFSET - offset to be added to all tar UIDs
> +# GID_OFFSET - offset to be added to all tar GIDs
>
> . @SCRIPTDIR@/vps-functions
>
> vzcheckvar VE_PRVT PRIVATE_TEMPLATE
>
> +chown_preload_if_needed()
> +{
> + [ -z "$UID_OFFSET" -o -z "$GID_OFFSET" ] && return
> +
> + # TODO use tar with appropriate option when it becomes available
> + #
> + # The goal is to get this merged into tar so we no longer
> + # need to do this preload. Whenever it happens, we will include
> + # a version check here as well
> + export LD_PRELOAD=libvzchown.so
> +}
> +
> create_prvt()
> {
> local TMP AVAIL NEEDED HEADER OPT
> @@ -75,6 +91,9 @@ create_prvt()
> [ "$AVAIL" -ge "$NEEDED" ] ||
> vzerror "Insufficient disk space in $VE_PRVT; available: $AVAIL, needed: $NEEDED" ${VZ_FS_NO_DISK_SPACE}
> CAT=cat
> +
> + chown_preload_if_needed
> +
> # Use pv to show nice progress bar if we can
> pv -V >/dev/null 2>&1 && CAT=pv
> chmod 700 "$VE_PRVT"
> diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
> index 42a7ed6..44c8a69 100644
> --- a/src/lib/Makefile.am
> +++ b/src/lib/Makefile.am
> @@ -70,6 +70,9 @@ libvzctl_la_LIBADD = $(XML_LIBS) $(CGROUP_LIBS) $(DL_LIBS)
>
> if HAVE_CGROUP
> libvzctl_la_SOURCES += cgroup.c hooks_ct.c
> +
> +lib_LTLIBRARIES += libvzchown.la
> +libvzchown_la_SOURCES = chown_preload.c
> endif
>
> if HAVE_VZ_KERNEL
> diff --git a/src/lib/chown_preload.c b/src/lib/chown_preload.c
> new file mode 100644
> index 0000000..4e2be4a
> --- /dev/null
> +++ b/src/lib/chown_preload.c
> @@ -0,0 +1,93 @@
> +/*
> + * Copyright (C) 2013, Parallels, 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, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + * Authors: Kir Kolyshkin and Glauber Costa
> + */
> +
> +#include <unistd.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +#include <dlfcn.h>
> +
> +static int (*real_chown)(const char *path, uid_t owner, gid_t group) = NULL;
> +static int (*real_fchown)(int fd, uid_t owner, gid_t group) = NULL;
> +static int (*real_lchown)(const char *path, uid_t owner, gid_t group) = NULL;
> +static int (*real_fchownat)(int dirfd, const char *pathname,
> + uid_t owner, gid_t group, int flags) = NULL;
> +
> +uid_t uid_offset = 0;
> +gid_t gid_offset = 0;
> +
> +static void __init(void)
> +{
> + char *uidstr, *gidstr;
> +
> + uidstr = getenv("UID_OFFSET");
> + gidstr = getenv("GID_OFFSET");
> + if (!uidstr || !gidstr) {
> + fprintf(stderr, "Environment variables UID_OFFSET "
> + "and GID_OFFSET are required -- aborting\n");
> + exit(33);
> + }
> + uid_offset = strtol(uidstr, NULL, 10);
> + gid_offset = strtol(gidstr, NULL, 10);
> +
> + real_chown = dlsym(RTLD_NEXT, "chown");
> + real_fchown = dlsym(RTLD_NEXT, "fchown");
> + real_lchown = dlsym(RTLD_NEXT, "lchown");
> + real_fchownat = dlsym(RTLD_NEXT, "fchownat");
> +
> + if (!real_chown || !real_fchown || !real_lchown || !real_fchownat) {
> + fprintf(stderr, "dlsym failed: %s\n", dlerror());
> + exit(34);
> + }
> +}
> +
> +int chown(const char *path, uid_t owner, gid_t group)
> +{
> + if (!real_chown)
> + __init();
> +
> + return real_chown(path, owner + uid_offset, group + gid_offset);
> +}
> +
> +int fchown(int fd, uid_t owner, gid_t group)
> +{
> + if (!real_fchown)
> + __init();
> +
> + return real_fchown(fd, owner + uid_offset, group + gid_offset);
> +}
> +
> +int lchown(const char *path, uid_t owner, gid_t group)
> +{
> + if (!real_lchown)
> + __init();
> +
> + return real_lchown(path, owner + uid_offset, group + gid_offset);
> +}
> +
> +int fchownat(int dirfd, const char *pathname,
> + uid_t owner, gid_t group, int flags)
> +{
> + if (!real_fchownat)
> + __init();
> +
> + return real_fchownat(dirfd, pathname,
> + owner + uid_offset, group + gid_offset, flags);
> +}
> diff --git a/src/lib/create.c b/src/lib/create.c
> index 0a0330f..7e28628 100644
> --- a/src/lib/create.c
> +++ b/src/lib/create.c
> @@ -98,7 +98,7 @@ static int fs_create(envid_t veid, vps_handler *h, fs_param *fs,
> char buf[PATH_LEN];
> int ret;
> char *arg[2];
> - char *env[4];
> + char *env[6];
> int quota = 0;
> int i;
> char *dst;
> @@ -106,8 +106,8 @@ static int fs_create(envid_t veid, vps_handler *h, fs_param *fs,
> const char *errmsg_ext = "[.gz|.bz2|.xz]";
> dq_param *dq = &vps_p->res.dq;
> int layout = vps_p->opt.layout;
> - unsigned int uid_offset = vps_p->res.misc.local_uid;
> - unsigned int gid_offset = vps_p->res.misc.local_gid;
> + unsigned long uid_offset = *vps_p->res.misc.local_uid;
> + unsigned long gid_offset = *vps_p->res.misc.local_gid;
> int ploop = (layout == VE_LAYOUT_PLOOP);
>
> if (ploop && (!dq->diskspace || dq->diskspace[1] <= 0)) {
> @@ -196,11 +196,18 @@ find:
> arg[0] = VPS_CREATE;
> arg[1] = NULL;
> snprintf(buf, sizeof(buf), "PRIVATE_TEMPLATE=%s", tarball);
> - env[0] = strdup(buf);
> + i = 0;
> + env[i++] = strdup(buf);
> snprintf(buf, sizeof(buf), "VE_PRVT=%s", dst);
> - env[1] = strdup(buf);
> - env[2] = strdup(ENV_PATH);
> - env[3] = NULL;
> + env[i++] = strdup(buf);
> + if (!is_vz_kernel(h) && h->can_join_userns) {
> + snprintf(buf, sizeof(buf), "UID_OFFSET=%lu", uid_offset);
> + env[i++] = strdup(buf);
> + snprintf(buf, sizeof(buf), "GID_OFFSET=%lu", gid_offset);
> + env[i++] = strdup(buf);
> + }
> + env[i++] = strdup(ENV_PATH);
> + env[i] = NULL;
> logger(0, 0, "Creating container private area (%s)", tmpl->ostmpl);
> ret = run_script(VPS_CREATE, arg, env, 0);
> free_arg(env);
> diff --git a/vzctl.spec b/vzctl.spec
> index f77d326..0a68427 100644
> --- a/vzctl.spec
> +++ b/vzctl.spec
> @@ -182,7 +182,7 @@ Requires: wget
> OpenVZ containers control utility core package
>
> %files core
> -%{_libdir}/libvzctl-*.so
> +%{_libdir}/libvz*.so
> %dir %{_lockdir}
> %dir %{_dumpdir}
> %dir %{_privdir}
More information about the Devel
mailing list