[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