hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/security/device_cgroup.c
....@@ -15,6 +15,8 @@
1515 #include <linux/rcupdate.h>
1616 #include <linux/mutex.h>
1717
18
+#ifdef CONFIG_CGROUP_DEVICE
19
+
1820 static DEFINE_MUTEX(devcgroup_mutex);
1921
2022 enum devcg_behavior {
....@@ -77,6 +79,17 @@
7779 kfree(ex);
7880 }
7981 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
+ }
8093 }
8194
8295 /*
....@@ -352,7 +365,8 @@
352365 {
353366 struct dev_exception_item *ex;
354367
355
- list_for_each_entry_rcu(ex, exceptions, list) {
368
+ list_for_each_entry_rcu(ex, exceptions, list,
369
+ lockdep_is_held(&devcgroup_mutex)) {
356370 if ((type & DEVCG_DEV_BLOCK) && !(ex->type & DEVCG_DEV_BLOCK))
357371 continue;
358372 if ((type & DEVCG_DEV_CHAR) && !(ex->type & DEVCG_DEV_CHAR))
....@@ -509,7 +523,7 @@
509523 * This is one of the three key functions for hierarchy implementation.
510524 * This function is responsible for re-evaluating all the cgroup's active
511525 * 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.
513527 */
514528 static void revalidate_active_exceptions(struct dev_cgroup *devcg)
515529 {
....@@ -600,11 +614,13 @@
600614 int count, rc = 0;
601615 struct dev_exception_item ex;
602616 struct dev_cgroup *parent = css_to_devcgroup(devcgroup->css.parent);
617
+ struct dev_cgroup tmp_devcgrp;
603618
604619 if (!capable(CAP_SYS_ADMIN))
605620 return -EPERM;
606621
607622 memset(&ex, 0, sizeof(ex));
623
+ memset(&tmp_devcgrp, 0, sizeof(tmp_devcgrp));
608624 b = buffer;
609625
610626 switch (*b) {
....@@ -616,15 +632,27 @@
616632
617633 if (!may_allow_all(parent))
618634 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);
622638 break;
639
+ }
623640
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);
626644 if (rc)
627645 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);
628656 break;
629657 case DEVCG_DENY:
630658 if (css_has_online_children(&devcgroup->css))
....@@ -792,7 +820,7 @@
792820 };
793821
794822 /**
795
- * __devcgroup_check_permission - checks if an inode operation is permitted
823
+ * devcgroup_legacy_check_permission - checks if an inode operation is permitted
796824 * @dev_cgroup: the dev cgroup to be tested against
797825 * @type: device type
798826 * @major: device major number
....@@ -801,8 +829,8 @@
801829 *
802830 * returns 0 on success, -EPERM case the operation is not permitted
803831 */
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)
806834 {
807835 struct dev_cgroup *dev_cgroup;
808836 bool rc;
....@@ -824,3 +852,25 @@
824852
825853 return 0;
826854 }
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) */