[Devel] [PATCH 3/6] run modified tar if upstream

Glauber Costa glommer at parallels.com
Mon Mar 11 04:01:24 PDT 2013


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 <glommer at parallels.com>
---
 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




More information about the Devel mailing list