Commit f429de66 authored by Pavel Emelyanov's avatar Pavel Emelyanov

creds: Support supplementary groups

Dumping them is performed via parasite, since calling the getgroups
is the only way of getting the complete list. Currently the nr of
groups to dump is limited explicitly with the size of shared memory
between crtools and parasite. This is MUCH more that we have seen
on real apps so far.

Restoring is done early, before restorer blob not to carry the undefined
array of grpous in there. This is OK, since groups do not affect us at
that point and are not affected by subsequent creds restore.
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 013d26bd
......@@ -8,6 +8,7 @@
#include <string.h>
#include <fcntl.h>
#include <grp.h>
#include <sys/types.h>
#include <sys/stat.h>
......@@ -1139,6 +1140,18 @@ static int prepare_creds(int pid, struct task_restore_core_args *args)
args->creds.cap_bnd = args->cap_bnd;
memcpy(args->cap_bnd, ce->cap_bnd, sizeof(args->cap_bnd));
/*
* We can set supplementary groups here. This won't affect any
* permission checks for us (we're still root) and will not be
* reset by subsequent creds changes in restorer.
*/
BUILD_BUG_ON(sizeof(*ce->groups) != sizeof(gid_t));
if (setgroups(ce->n_groups, ce->groups) < 0) {
pr_perror("Can't set supplementary groups");
return -1;
}
creds_entry__free_unpacked(ce, NULL);
/* XXX -- validate creds here? */
......
......@@ -80,8 +80,12 @@ struct parasite_dump_misc {
u32 pgid;
};
#define PARASITE_MAX_GROUPS (PAGE_SIZE / sizeof(unsigned int))
struct parasite_dump_creds {
unsigned int secbits;
unsigned int ngroups;
unsigned int groups[PARASITE_MAX_GROUPS];
};
struct parasite_dump_tid_info {
......
......@@ -541,6 +541,16 @@ int parasite_dump_creds(struct parasite_ctl *ctl, CredsEntry *ce)
return -1;
ce->secbits = pc->secbits;
ce->n_groups = pc->ngroups;
/*
* Achtung! We leak the parasite args pointer to the caller.
* It's not safe in general, but in our case is OK, since the
* latter doesn't go to parasite before using the data in it.
*/
BUILD_BUG_ON(sizeof(ce->groups[0]) != sizeof(pc->groups[0]));
ce->groups = pc->groups;
return 0;
}
......
......@@ -314,8 +314,35 @@ static int dump_misc(struct parasite_dump_misc *args)
static int dump_creds(struct parasite_dump_creds *args)
{
int ret;
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;
}
return 0;
grps_err:
pr_err("Error calling getgroups (%d)\n", ret);
return -1;
}
static int dump_tid_info(struct parasite_dump_tid_info *args)
......
......@@ -14,4 +14,6 @@ message creds_entry {
repeated uint32 cap_bnd = 12;
required uint32 secbits = 13;
repeated uint32 groups = 14;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment