Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fbfd6dee authored by Wang Weiyang's avatar Wang Weiyang Committed by Greg Kroah-Hartman
Browse files

device_cgroup: Roll back to original exceptions after copy failure



commit e68bfbd3b3c3a0ec3cf8c230996ad8cabe90322f upstream.

When add the 'a *:* rwm' entry to devcgroup A's whitelist, at first A's
exceptions will be cleaned and A's behavior is changed to
DEVCG_DEFAULT_ALLOW. Then parent's exceptions will be copyed to A's
whitelist. If copy failure occurs, just return leaving A to grant
permissions to all devices. And A may grant more permissions than
parent.

Backup A's whitelist and recover original exceptions after copy
failure.

Cc: stable@vger.kernel.org
Fixes: 4cef7299 ("device_cgroup: add proper checking when changing default behavior")
Signed-off-by: default avatarWang Weiyang <wangweiyang2@huawei.com>
Reviewed-by: default avatarAristeu Rozanski <aris@redhat.com>
Signed-off-by: default avatarPaul Moore <paul@paul-moore.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 5e450045
Loading
Loading
Loading
Loading
+29 −4
Original line number Diff line number Diff line
@@ -79,6 +79,17 @@ static int dev_exceptions_copy(struct list_head *dest, struct list_head *orig)
	return -ENOMEM;
}

static void dev_exceptions_move(struct list_head *dest, struct list_head *orig)
{
	struct dev_exception_item *ex, *tmp;

	lockdep_assert_held(&devcgroup_mutex);

	list_for_each_entry_safe(ex, tmp, orig, list) {
		list_move_tail(&ex->list, dest);
	}
}

/*
 * called under devcgroup_mutex
 */
@@ -601,11 +612,13 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
	int count, rc = 0;
	struct dev_exception_item ex;
	struct dev_cgroup *parent = css_to_devcgroup(devcgroup->css.parent);
	struct dev_cgroup tmp_devcgrp;

	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;

	memset(&ex, 0, sizeof(ex));
	memset(&tmp_devcgrp, 0, sizeof(tmp_devcgrp));
	b = buffer;

	switch (*b) {
@@ -617,15 +630,27 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,

			if (!may_allow_all(parent))
				return -EPERM;
			dev_exception_clean(devcgroup);
			if (!parent) {
				devcgroup->behavior = DEVCG_DEFAULT_ALLOW;
			if (!parent)
				dev_exception_clean(devcgroup);
				break;
			}

			INIT_LIST_HEAD(&tmp_devcgrp.exceptions);
			rc = dev_exceptions_copy(&tmp_devcgrp.exceptions,
						 &devcgroup->exceptions);
			if (rc)
				return rc;
			dev_exception_clean(devcgroup);
			rc = dev_exceptions_copy(&devcgroup->exceptions,
						 &parent->exceptions);
			if (rc)
			if (rc) {
				dev_exceptions_move(&devcgroup->exceptions,
						    &tmp_devcgrp.exceptions);
				return rc;
			}
			devcgroup->behavior = DEVCG_DEFAULT_ALLOW;
			dev_exception_clean(&tmp_devcgrp);
			break;
		case DEVCG_DENY:
			if (css_has_online_children(&devcgroup->css))