aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--security/device_cgroup.c41
1 files changed, 38 insertions, 3 deletions
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index 6b1266dd92bb..9134dbf70d3e 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -463,6 +463,37 @@ static int parent_has_perm(struct dev_cgroup *childcg,
463} 463}
464 464
465/** 465/**
466 * parent_allows_removal - verify if it's ok to remove an exception
467 * @childcg: child cgroup from where the exception will be removed
468 * @ex: exception being removed
469 *
470 * When removing an exception in cgroups with default ALLOW policy, it must
471 * be checked if removing it will give the child cgroup more access than the
472 * parent.
473 *
474 * Return: true if it's ok to remove exception, false otherwise
475 */
476static bool parent_allows_removal(struct dev_cgroup *childcg,
477 struct dev_exception_item *ex)
478{
479 struct dev_cgroup *parent = css_to_devcgroup(css_parent(&childcg->css));
480
481 if (!parent)
482 return true;
483
484 /* It's always allowed to remove access to devices */
485 if (childcg->behavior == DEVCG_DEFAULT_DENY)
486 return true;
487
488 /*
489 * Make sure you're not removing part or a whole exception existing in
490 * the parent cgroup
491 */
492 return !match_exception_partial(&parent->exceptions, ex->type,
493 ex->major, ex->minor, ex->access);
494}
495
496/**
466 * may_allow_all - checks if it's possible to change the behavior to 497 * may_allow_all - checks if it's possible to change the behavior to
467 * allow based on parent's rules. 498 * allow based on parent's rules.
468 * @parent: device cgroup's parent 499 * @parent: device cgroup's parent
@@ -697,17 +728,21 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
697 728
698 switch (filetype) { 729 switch (filetype) {
699 case DEVCG_ALLOW: 730 case DEVCG_ALLOW:
700 if (!parent_has_perm(devcgroup, &ex))
701 return -EPERM;
702 /* 731 /*
703 * If the default policy is to allow by default, try to remove 732 * If the default policy is to allow by default, try to remove
704 * an matching exception instead. And be silent about it: we 733 * an matching exception instead. And be silent about it: we
705 * don't want to break compatibility 734 * don't want to break compatibility
706 */ 735 */
707 if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) { 736 if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) {
737 /* Check if the parent allows removing it first */
738 if (!parent_allows_removal(devcgroup, &ex))
739 return -EPERM;
708 dev_exception_rm(devcgroup, &ex); 740 dev_exception_rm(devcgroup, &ex);
709 return 0; 741 break;
710 } 742 }
743
744 if (!parent_has_perm(devcgroup, &ex))
745 return -EPERM;
711 rc = dev_exception_add(devcgroup, &ex); 746 rc = dev_exception_add(devcgroup, &ex);
712 break; 747 break;
713 case DEVCG_DENY: 748 case DEVCG_DENY: