If we are running upstream with user namespaces, we need to run a modified version of tar to extract the files. To avoid compatibility problems, we will resort to LD_PRELOAD if a recent tar is not available (if ever).
Signed-off-by: Glauber Costa <[email protected]> --- scripts/vps-create.in | 18 ++++++++++++ src/lib/Makefile.am | 3 ++ src/lib/chown_preload.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ src/lib/create.c | 17 ++++++++---- 4 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 src/lib/chown_preload.c diff --git a/scripts/vps-create.in b/scripts/vps-create.in index 126f048..08edfbe 100755 --- a/scripts/vps-create.in +++ b/scripts/vps-create.in @@ -22,11 +22,26 @@ # 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() +{ + if [ "xUID_OFFSET" == "x" ]; then return; fi + if [ "xGID_OFFSET" == "x" ]; then return; fi + + # 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 +90,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..429de7f 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..0bc5d0d --- /dev/null +++ b/src/lib/chown_preload.c @@ -0,0 +1,73 @@ +#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..1f22463 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; @@ -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=%d", uid_offset); + env[i++] = strdup(buf); + snprintf(buf, sizeof(buf), "GID_OFFSET=%d", 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); -- 1.7.11.7 _______________________________________________ Devel mailing list [email protected] https://lists.openvz.org/mailman/listinfo/devel
