.. | .. |
---|
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) */ |
---|