Due to restrictions imposed by several kernel APIs CRIU uses, the tools can only work with run with root privileges. The plan is to provide user-mode, but it will have restrictions.
In the latter case, the following security restrictions would apply:
Legend: cr_* -- ids of the calling user; others -- ids of process that we're trying to dump/restore;
- criu will refuse to dump/restore process if [se]?uid is not equal to cr_uid
- criu will refuse to dump/restore process if [se]?gid is not equal to cr_gid or cr_groups do not contain it
- criu will refuse to restore process if cr_groups don't contain groups
- criu will refuse to dump/restore any bits set in any capability set
See also
CRIU has security issues when working with user namespaces and selinux
Code example
Here is a simplified version of code from security.c.
bool check_uids()
{
if (cr_uid == 0)
return true;
if (cr_uid == ruid && cr_uid == suid && cr_uid == eid)
return true;
return false;
}
bool check_gids()
{
if (cr_gid == 0)
return true;
if ((contains(cr_groups, rgid) || cr_gid == rgid) &&
(contains(cr_groups, egid) || cr_gid == egid) &&
(contains(cr_groups, sgid) || cr_gid == sgid))
return true;
return false;
}
/*
* There is no need to check groups on dump, because if uids and gids match
* then groups will match too. Btw, getting groups on dump is problematic.
* We can't parse proc, as it contains only first 32 groups. And we can't use
* getgrouplist, as it reads /etc/group which depends on the namespace.
*
* On restore we're getting groups from imgs and can check if user didn't add
* wrong groups by modifying images.
*/
bool check_groups()
{
if (cr_gid == 0)
return true;
for (i = 0; i < ngroups; ++i) {
if (!contains(cr_groups, groups[i]))
return false;
}
return true;
}
bool check_caps()
{
/*
* Impose the most strict requirements for now.
* "Real" root user can use any caps, other users may
* use none. Later we will implement more sophisticated
* security model.
*/
if (cr_uid == 0 && cr_gid == 0)
return true;
for (i = 0; i < CR_CAP_SIZE; i++) {
if (inh[i] != 0 || eff[i] != 0 || prm[i] != 0)
return false;
}
return true;
}
bool may_dump()
{
return check_uids() &&
check_gids() &&
check_caps();
}
bool may_restore()
{
return check_uids() &&
check_gids() &&
check_groups() &&
check_caps();
}