Security

Revision as of 19:22, 10 December 2015 by Xemul (talk | contribs)

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();
}