diff options
-rw-r--r-- | security/device_cgroup.c | 41 |
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 | */ | ||
476 | static 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: |