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: |
