|
@@ -462,6 +462,37 @@ static int parent_has_perm(struct dev_cgroup *childcg,
|
|
|
return verify_new_ex(parent, ex, childcg->behavior);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * parent_allows_removal - verify if it's ok to remove an exception
|
|
|
+ * @childcg: child cgroup from where the exception will be removed
|
|
|
+ * @ex: exception being removed
|
|
|
+ *
|
|
|
+ * When removing an exception in cgroups with default ALLOW policy, it must
|
|
|
+ * be checked if removing it will give the child cgroup more access than the
|
|
|
+ * parent.
|
|
|
+ *
|
|
|
+ * Return: true if it's ok to remove exception, false otherwise
|
|
|
+ */
|
|
|
+static bool parent_allows_removal(struct dev_cgroup *childcg,
|
|
|
+ struct dev_exception_item *ex)
|
|
|
+{
|
|
|
+ struct dev_cgroup *parent = css_to_devcgroup(css_parent(&childcg->css));
|
|
|
+
|
|
|
+ if (!parent)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ /* It's always allowed to remove access to devices */
|
|
|
+ if (childcg->behavior == DEVCG_DEFAULT_DENY)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Make sure you're not removing part or a whole exception existing in
|
|
|
+ * the parent cgroup
|
|
|
+ */
|
|
|
+ return !match_exception_partial(&parent->exceptions, ex->type,
|
|
|
+ ex->major, ex->minor, ex->access);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* may_allow_all - checks if it's possible to change the behavior to
|
|
|
* allow based on parent's rules.
|
|
@@ -697,17 +728,21 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
|
|
|
|
|
|
switch (filetype) {
|
|
|
case DEVCG_ALLOW:
|
|
|
- if (!parent_has_perm(devcgroup, &ex))
|
|
|
- return -EPERM;
|
|
|
/*
|
|
|
* If the default policy is to allow by default, try to remove
|
|
|
* an matching exception instead. And be silent about it: we
|
|
|
* don't want to break compatibility
|
|
|
*/
|
|
|
if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) {
|
|
|
+ /* Check if the parent allows removing it first */
|
|
|
+ if (!parent_allows_removal(devcgroup, &ex))
|
|
|
+ return -EPERM;
|
|
|
dev_exception_rm(devcgroup, &ex);
|
|
|
- return 0;
|
|
|
+ break;
|
|
|
}
|
|
|
+
|
|
|
+ if (!parent_has_perm(devcgroup, &ex))
|
|
|
+ return -EPERM;
|
|
|
rc = dev_exception_add(devcgroup, &ex);
|
|
|
break;
|
|
|
case DEVCG_DENY:
|