[CRIU] [PATCH v1 11/17] core: Dump task credential xids from criu namespace

Kirill Tkhai ktkhai at virtuozzo.com
Thu Jan 12 09:53:55 PST 2017


When a task is in NS_OTHER namespace, and there is no
mapping between the namespace and its parent, task
does not know its own uids/gids.

Collect them from NS_CRIU instead of this, and dump
their values in NS_ROOT.

Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
---
 criu/cr-dump.c          |   83 +++++++++++++++++++++++++++++++++++++++++++++++
 criu/include/parasite.h |   25 --------------
 criu/parasite-syscall.c |   22 ++----------
 criu/pie/parasite.c     |   50 ----------------------------
 4 files changed, 87 insertions(+), 93 deletions(-)

diff --git a/criu/cr-dump.c b/criu/cr-dump.c
index 18ff6d6d1..8bebc1749 100644
--- a/criu/cr-dump.c
+++ b/criu/cr-dump.c
@@ -334,6 +334,83 @@ static int dump_task_rlimits(int pid, TaskRlimitsEntry *rls)
 	return 0;
 }
 
+static int dump_task_cred_ids(pid_t pid, pid_t tid, CredsEntry *ce)
+{
+	int done = 0, ret;
+	int n_groups = 0;
+	struct bfd f;
+	char *str;
+
+	if (tid == -1)
+		f.fd = open_proc(pid, "status");
+	else
+		f.fd = open_proc_path(pid, "task/%d", tid);
+	if (f.fd < 0)
+		return -1;
+	if (bfdopenr(&f))
+		return -1;
+
+	while (done < 3) {
+		str = breadline(&f);
+		if (str == NULL)
+			break;
+		if (IS_ERR(str))
+			goto out;
+
+		if (!strncmp(str, "Uid:", 4)) {
+			if (sscanf(str + 4, "%u\t%u\t%u\t%u\t", &ce->uid, &ce->euid,
+								&ce->suid, &ce->fsuid) != 4)
+				goto out;
+			ce->uid   = userns_uid(ce->uid);
+			ce->euid  = userns_uid(ce->euid);
+			ce->suid  = userns_uid(ce->suid);
+			ce->fsuid = userns_uid(ce->fsuid);
+			done++;
+		}
+
+		if (!strncmp(str, "Gid:", 4)) {
+			if (sscanf(str + 4, "%u\t%u\t%u\t%u\t", &ce->gid, &ce->egid,
+								&ce->sgid, &ce->fsgid) != 4)
+				goto out;
+			ce->gid   = userns_gid(ce->gid);
+			ce->egid  = userns_gid(ce->egid);
+			ce->sgid  = userns_gid(ce->sgid);
+			ce->fsgid = userns_gid(ce->fsgid);
+			done++;
+		}
+
+		if (!strncmp(str, "Groups:", 7)) {
+			gid_t gid, *groups = NULL;
+			char *p = str + 7;
+			int size;
+
+			if (n_groups)
+				goto out;
+			do {
+				ret = sscanf(p, "%u%n", &gid, &size);
+				if (ret == 1) {
+					n_groups++;
+					p += size;
+					groups = xrealloc(groups, n_groups * sizeof(gid));
+					if (!groups)
+						goto out;
+					groups[n_groups-1] = userns_gid(gid);
+				}
+			} while (ret == 1);
+			ce->groups = groups;
+			ce->n_groups = n_groups;
+			done++;
+		}
+	}
+out:
+	bclose(&f);
+	if (done < 3) {
+		pr_err("Can't get task's credentials\n");
+		return -1;
+	}
+	return 0;
+}
+
 static int dump_pid_misc(pid_t pid, TaskCoreEntry *tc)
 {
 	int ret;
@@ -756,6 +833,10 @@ static int dump_task_core_all(struct parasite_ctl *ctl,
 	if (ret)
 		goto err;
 
+	ret = dump_task_cred_ids(item->pid.real, -1, core->thread_core->creds);
+	if (ret)
+		goto err;
+
 	img = img_from_set(cr_imgset, CR_FD_CORE);
 	ret = pb_write_one(img, core, PB_CORE);
 	if (ret < 0)
@@ -833,6 +914,8 @@ static int dump_task_thread(struct parasite_ctl *parasite_ctl,
 	}
 	pstree_insert_pid(tid->virt, tid);
 
+	ret = dump_task_cred_ids(item->pid.real, tid->real, core->thread_core->creds);
+
 	img = open_image(CR_FD_CORE, O_DUMP, tid->virt);
 	if (!img)
 		goto err;
diff --git a/criu/include/parasite.h b/criu/include/parasite.h
index cd6d793f8..bd18cc6ce 100644
--- a/criu/include/parasite.h
+++ b/criu/include/parasite.h
@@ -126,14 +126,6 @@ struct parasite_dump_misc {
 	int dumpable;
 };
 
-/*
- * Calculate how long we can make the groups array in parasite_dump_creds
- * and still fit the struct in one page
- */
-#define PARASITE_MAX_GROUPS							\
-	((PAGE_SIZE - sizeof(struct parasite_dump_thread) -			\
-	 offsetof(struct parasite_dump_creds, groups)) / sizeof(unsigned int)) /* groups */
-
 struct parasite_dump_creds {
 	unsigned int		cap_last_cap;
 
@@ -142,24 +134,7 @@ struct parasite_dump_creds {
 	u32			cap_eff[CR_CAP_SIZE];
 	u32			cap_bnd[CR_CAP_SIZE];
 
-	int			uids[4];
-	int			gids[4];
 	unsigned int		secbits;
-	unsigned int		ngroups;
-	/*
-	 * FIXME -- this structure is passed to parasite code
-	 * through parasite args area so in parasite_dump_creds()
-	 * call we check for size of this data fits the size of
-	 * the area. Unfortunatelly, we _actually_ use more bytes
-	 * than the sizeof() -- we put PARASITE_MAX_GROUPS int-s
-	 * in there, so the size check is not correct.
-	 *
-	 * However, all this works simply because we make sure
-	 * the PARASITE_MAX_GROUPS is so, that the total amount
-	 * of memory in use doesn't exceed the PAGE_SIZE and the
-	 * args area is at least one page (PARASITE_ARG_SIZE_MIN).
-	 */
-	unsigned int		groups[0];
 };
 
 struct parasite_dump_thread {
diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c
index a5253241b..4ccd20111 100644
--- a/criu/parasite-syscall.c
+++ b/criu/parasite-syscall.c
@@ -103,9 +103,8 @@ static void sigchld_handler(int signal, siginfo_t *siginfo, void *data)
 	exit(1);
 }
 
-static int alloc_groups_copy_creds(CredsEntry *ce, struct parasite_dump_creds *c)
+static int copy_caps(CredsEntry *ce, struct parasite_dump_creds *c)
 {
-	BUILD_BUG_ON(sizeof(ce->groups[0]) != sizeof(c->groups[0]));
 	BUILD_BUG_ON(sizeof(ce->cap_inh[0]) != sizeof(c->cap_inh[0]));
 	BUILD_BUG_ON(sizeof(ce->cap_prm[0]) != sizeof(c->cap_prm[0]));
 	BUILD_BUG_ON(sizeof(ce->cap_eff[0]) != sizeof(c->cap_eff[0]));
@@ -122,20 +121,7 @@ static int alloc_groups_copy_creds(CredsEntry *ce, struct parasite_dump_creds *c
 	memcpy(ce->cap_bnd, c->cap_bnd, sizeof(c->cap_bnd[0]) * CR_CAP_SIZE);
 
 	ce->secbits	= c->secbits;
-	ce->n_groups	= c->ngroups;
-
-	ce->groups	= xmemdup(c->groups, sizeof(c->groups[0]) * c->ngroups);
-
-	ce->uid		= c->uids[0];
-	ce->gid		= c->gids[0];
-	ce->euid	= c->uids[1];
-	ce->egid	= c->gids[1];
-	ce->suid	= c->uids[2];
-	ce->sgid	= c->gids[2];
-	ce->fsuid	= c->uids[3];
-	ce->fsgid	= c->gids[3];
-
-	return ce->groups ? 0 : -ENOMEM;
+	return 0;
 }
 
 int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, CoreEntry *core)
@@ -154,7 +140,7 @@ int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, CoreEn
 	if (ret < 0)
 		return ret;
 
-	ret = alloc_groups_copy_creds(tc->creds, pc);
+	ret = copy_caps(tc->creds, pc);
 	if (ret) {
 		pr_err("Can't copy creds for thread leader %d\n", pid);
 		return -1;
@@ -194,7 +180,7 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
 		goto err_rth;
 	}
 
-	ret = alloc_groups_copy_creds(creds, pc);
+	ret = copy_caps(creds, pc);
 	if (ret) {
 		pr_err("Can't copy creds for thread %d\n", pid);
 		goto err_rth;
diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c
index e84d63405..c8c51701a 100644
--- a/criu/pie/parasite.c
+++ b/criu/pie/parasite.c
@@ -225,57 +225,7 @@ static int dump_creds(struct parasite_dump_creds *args)
 
 	args->secbits = sys_prctl(PR_GET_SECUREBITS, 0, 0, 0, 0);
 
-	ret = sys_getgroups(0, NULL);
-	if (ret < 0)
-		goto grps_err;
-
-	args->ngroups = ret;
-	if (args->ngroups >= PARASITE_MAX_GROUPS) {
-		pr_err("Too many groups in task %d\n", (int)args->ngroups);
-		return -1;
-	}
-
-	ret = sys_getgroups(args->ngroups, args->groups);
-	if (ret < 0)
-		goto grps_err;
-
-	if (ret != args->ngroups) {
-		pr_err("Groups changed on the fly %d -> %d\n",
-				args->ngroups, ret);
-		return -1;
-	}
-
-	ret = sys_getresuid(&args->uids[0], &args->uids[1], &args->uids[2]);
-	if (ret) {
-		pr_err("Unable to get uids: %d\n", ret);
-		return -1;
-	}
-
-	args->uids[3] = sys_setfsuid(-1L);
-
-	/*
-	 * FIXME In https://github.com/xemul/criu/issues/95 it is
-	 * been reported that only low 16 bits are set upon syscall
-	 * on ARMv7.
-	 *
-	 * We may rather need implement builtin-memset and clear the
-	 * whole memory needed here.
-	 */
-	args->gids[0] = args->gids[1] = args->gids[2] = args->gids[3] = 0;
-
-	ret = sys_getresgid(&args->gids[0], &args->gids[1], &args->gids[2]);
-	if (ret) {
-		pr_err("Unable to get uids: %d\n", ret);
-		return -1;
-	}
-
-	args->gids[3] = sys_setfsgid(-1L);
-
 	return 0;
-
-grps_err:
-	pr_err("Error calling getgroups (%d)\n", ret);
-	return -1;
 }
 
 static int fill_fds_opts(struct parasite_drain_fd *fds, struct fd_opts *opts)



More information about the CRIU mailing list