| .. | .. |
|---|
| 15 | 15 | #include <linux/rcupdate.h> |
|---|
| 16 | 16 | #include <linux/mutex.h> |
|---|
| 17 | 17 | |
|---|
| 18 | +#ifdef CONFIG_CGROUP_DEVICE |
|---|
| 19 | + |
|---|
| 18 | 20 | static DEFINE_MUTEX(devcgroup_mutex); |
|---|
| 19 | 21 | |
|---|
| 20 | 22 | enum devcg_behavior { |
|---|
| .. | .. |
|---|
| 77 | 79 | kfree(ex); |
|---|
| 78 | 80 | } |
|---|
| 79 | 81 | return -ENOMEM; |
|---|
| 82 | +} |
|---|
| 83 | + |
|---|
| 84 | +static void dev_exceptions_move(struct list_head *dest, struct list_head *orig) |
|---|
| 85 | +{ |
|---|
| 86 | + struct dev_exception_item *ex, *tmp; |
|---|
| 87 | + |
|---|
| 88 | + lockdep_assert_held(&devcgroup_mutex); |
|---|
| 89 | + |
|---|
| 90 | + list_for_each_entry_safe(ex, tmp, orig, list) { |
|---|
| 91 | + list_move_tail(&ex->list, dest); |
|---|
| 92 | + } |
|---|
| 80 | 93 | } |
|---|
| 81 | 94 | |
|---|
| 82 | 95 | /* |
|---|
| .. | .. |
|---|
| 352 | 365 | { |
|---|
| 353 | 366 | struct dev_exception_item *ex; |
|---|
| 354 | 367 | |
|---|
| 355 | | - list_for_each_entry_rcu(ex, exceptions, list) { |
|---|
| 368 | + list_for_each_entry_rcu(ex, exceptions, list, |
|---|
| 369 | + lockdep_is_held(&devcgroup_mutex)) { |
|---|
| 356 | 370 | if ((type & DEVCG_DEV_BLOCK) && !(ex->type & DEVCG_DEV_BLOCK)) |
|---|
| 357 | 371 | continue; |
|---|
| 358 | 372 | if ((type & DEVCG_DEV_CHAR) && !(ex->type & DEVCG_DEV_CHAR)) |
|---|
| .. | .. |
|---|
| 509 | 523 | * This is one of the three key functions for hierarchy implementation. |
|---|
| 510 | 524 | * This function is responsible for re-evaluating all the cgroup's active |
|---|
| 511 | 525 | * exceptions due to a parent's exception change. |
|---|
| 512 | | - * Refer to Documentation/cgroup-v1/devices.txt for more details. |
|---|
| 526 | + * Refer to Documentation/admin-guide/cgroup-v1/devices.rst for more details. |
|---|
| 513 | 527 | */ |
|---|
| 514 | 528 | static void revalidate_active_exceptions(struct dev_cgroup *devcg) |
|---|
| 515 | 529 | { |
|---|
| .. | .. |
|---|
| 600 | 614 | int count, rc = 0; |
|---|
| 601 | 615 | struct dev_exception_item ex; |
|---|
| 602 | 616 | struct dev_cgroup *parent = css_to_devcgroup(devcgroup->css.parent); |
|---|
| 617 | + struct dev_cgroup tmp_devcgrp; |
|---|
| 603 | 618 | |
|---|
| 604 | 619 | if (!capable(CAP_SYS_ADMIN)) |
|---|
| 605 | 620 | return -EPERM; |
|---|
| 606 | 621 | |
|---|
| 607 | 622 | memset(&ex, 0, sizeof(ex)); |
|---|
| 623 | + memset(&tmp_devcgrp, 0, sizeof(tmp_devcgrp)); |
|---|
| 608 | 624 | b = buffer; |
|---|
| 609 | 625 | |
|---|
| 610 | 626 | switch (*b) { |
|---|
| .. | .. |
|---|
| 616 | 632 | |
|---|
| 617 | 633 | if (!may_allow_all(parent)) |
|---|
| 618 | 634 | return -EPERM; |
|---|
| 619 | | - dev_exception_clean(devcgroup); |
|---|
| 620 | | - devcgroup->behavior = DEVCG_DEFAULT_ALLOW; |
|---|
| 621 | | - if (!parent) |
|---|
| 635 | + if (!parent) { |
|---|
| 636 | + devcgroup->behavior = DEVCG_DEFAULT_ALLOW; |
|---|
| 637 | + dev_exception_clean(devcgroup); |
|---|
| 622 | 638 | break; |
|---|
| 639 | + } |
|---|
| 623 | 640 | |
|---|
| 624 | | - rc = dev_exceptions_copy(&devcgroup->exceptions, |
|---|
| 625 | | - &parent->exceptions); |
|---|
| 641 | + INIT_LIST_HEAD(&tmp_devcgrp.exceptions); |
|---|
| 642 | + rc = dev_exceptions_copy(&tmp_devcgrp.exceptions, |
|---|
| 643 | + &devcgroup->exceptions); |
|---|
| 626 | 644 | if (rc) |
|---|
| 627 | 645 | return rc; |
|---|
| 646 | + dev_exception_clean(devcgroup); |
|---|
| 647 | + rc = dev_exceptions_copy(&devcgroup->exceptions, |
|---|
| 648 | + &parent->exceptions); |
|---|
| 649 | + if (rc) { |
|---|
| 650 | + dev_exceptions_move(&devcgroup->exceptions, |
|---|
| 651 | + &tmp_devcgrp.exceptions); |
|---|
| 652 | + return rc; |
|---|
| 653 | + } |
|---|
| 654 | + devcgroup->behavior = DEVCG_DEFAULT_ALLOW; |
|---|
| 655 | + dev_exception_clean(&tmp_devcgrp); |
|---|
| 628 | 656 | break; |
|---|
| 629 | 657 | case DEVCG_DENY: |
|---|
| 630 | 658 | if (css_has_online_children(&devcgroup->css)) |
|---|
| .. | .. |
|---|
| 792 | 820 | }; |
|---|
| 793 | 821 | |
|---|
| 794 | 822 | /** |
|---|
| 795 | | - * __devcgroup_check_permission - checks if an inode operation is permitted |
|---|
| 823 | + * devcgroup_legacy_check_permission - checks if an inode operation is permitted |
|---|
| 796 | 824 | * @dev_cgroup: the dev cgroup to be tested against |
|---|
| 797 | 825 | * @type: device type |
|---|
| 798 | 826 | * @major: device major number |
|---|
| .. | .. |
|---|
| 801 | 829 | * |
|---|
| 802 | 830 | * returns 0 on success, -EPERM case the operation is not permitted |
|---|
| 803 | 831 | */ |
|---|
| 804 | | -int __devcgroup_check_permission(short type, u32 major, u32 minor, |
|---|
| 805 | | - short access) |
|---|
| 832 | +static int devcgroup_legacy_check_permission(short type, u32 major, u32 minor, |
|---|
| 833 | + short access) |
|---|
| 806 | 834 | { |
|---|
| 807 | 835 | struct dev_cgroup *dev_cgroup; |
|---|
| 808 | 836 | bool rc; |
|---|
| .. | .. |
|---|
| 824 | 852 | |
|---|
| 825 | 853 | return 0; |
|---|
| 826 | 854 | } |
|---|
| 855 | + |
|---|
| 856 | +#endif /* CONFIG_CGROUP_DEVICE */ |
|---|
| 857 | + |
|---|
| 858 | +#if defined(CONFIG_CGROUP_DEVICE) || defined(CONFIG_CGROUP_BPF) |
|---|
| 859 | + |
|---|
| 860 | +int devcgroup_check_permission(short type, u32 major, u32 minor, short access) |
|---|
| 861 | +{ |
|---|
| 862 | + int rc = BPF_CGROUP_RUN_PROG_DEVICE_CGROUP(type, major, minor, access); |
|---|
| 863 | + |
|---|
| 864 | + if (rc) |
|---|
| 865 | + return -EPERM; |
|---|
| 866 | + |
|---|
| 867 | + #ifdef CONFIG_CGROUP_DEVICE |
|---|
| 868 | + return devcgroup_legacy_check_permission(type, major, minor, access); |
|---|
| 869 | + |
|---|
| 870 | + #else /* CONFIG_CGROUP_DEVICE */ |
|---|
| 871 | + return 0; |
|---|
| 872 | + |
|---|
| 873 | + #endif /* CONFIG_CGROUP_DEVICE */ |
|---|
| 874 | +} |
|---|
| 875 | +EXPORT_SYMBOL(devcgroup_check_permission); |
|---|
| 876 | +#endif /* defined(CONFIG_CGROUP_DEVICE) || defined(CONFIG_CGROUP_BPF) */ |
|---|