Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * device_cgroup.c - device cgroup subsystem
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright 2007 IBM Corp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #include <linux/device_cgroup.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <linux/cgroup.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/ctype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <linux/seq_file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/rcupdate.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #ifdef CONFIG_CGROUP_DEVICE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) static DEFINE_MUTEX(devcgroup_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) enum devcg_behavior {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 	DEVCG_DEFAULT_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 	DEVCG_DEFAULT_ALLOW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 	DEVCG_DEFAULT_DENY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29)  * exception list locking rules:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30)  * hold devcgroup_mutex for update/read.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31)  * hold rcu_read_lock() for read.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) struct dev_exception_item {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 	u32 major, minor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 	short type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 	short access;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 	struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	struct rcu_head rcu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) struct dev_cgroup {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 	struct cgroup_subsys_state css;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	struct list_head exceptions;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 	enum devcg_behavior behavior;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	return s ? container_of(s, struct dev_cgroup, css) : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) static inline struct dev_cgroup *task_devcgroup(struct task_struct *task)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	return css_to_devcgroup(task_css(task, devices_cgrp_id));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59)  * called under devcgroup_mutex
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) static int dev_exceptions_copy(struct list_head *dest, struct list_head *orig)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	struct dev_exception_item *ex, *tmp, *new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 	lockdep_assert_held(&devcgroup_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 	list_for_each_entry(ex, orig, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 		new = kmemdup(ex, sizeof(*ex), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 		if (!new)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 			goto free_and_exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 		list_add_tail(&new->list, dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) free_and_exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	list_for_each_entry_safe(ex, tmp, dest, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 		list_del(&ex->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 		kfree(ex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85)  * called under devcgroup_mutex
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) static int dev_exception_add(struct dev_cgroup *dev_cgroup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 			     struct dev_exception_item *ex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	struct dev_exception_item *excopy, *walk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	lockdep_assert_held(&devcgroup_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	excopy = kmemdup(ex, sizeof(*ex), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	if (!excopy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	list_for_each_entry(walk, &dev_cgroup->exceptions, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 		if (walk->type != ex->type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 		if (walk->major != ex->major)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 		if (walk->minor != ex->minor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 		walk->access |= ex->access;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 		kfree(excopy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 		excopy = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	if (excopy != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 		list_add_tail_rcu(&excopy->list, &dev_cgroup->exceptions);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)  * called under devcgroup_mutex
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static void dev_exception_rm(struct dev_cgroup *dev_cgroup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 			     struct dev_exception_item *ex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	struct dev_exception_item *walk, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	lockdep_assert_held(&devcgroup_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	list_for_each_entry_safe(walk, tmp, &dev_cgroup->exceptions, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 		if (walk->type != ex->type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 		if (walk->major != ex->major)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 		if (walk->minor != ex->minor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 		walk->access &= ~ex->access;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 		if (!walk->access) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 			list_del_rcu(&walk->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 			kfree_rcu(walk, rcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) static void __dev_exception_clean(struct dev_cgroup *dev_cgroup)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	struct dev_exception_item *ex, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 	list_for_each_entry_safe(ex, tmp, &dev_cgroup->exceptions, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 		list_del_rcu(&ex->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 		kfree_rcu(ex, rcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)  * dev_exception_clean - frees all entries of the exception list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)  * @dev_cgroup: dev_cgroup with the exception list to be cleaned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)  * called under devcgroup_mutex
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) static void dev_exception_clean(struct dev_cgroup *dev_cgroup)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	lockdep_assert_held(&devcgroup_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	__dev_exception_clean(dev_cgroup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) static inline bool is_devcg_online(const struct dev_cgroup *devcg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	return (devcg->behavior != DEVCG_DEFAULT_NONE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)  * devcgroup_online - initializes devcgroup's behavior and exceptions based on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)  * 		      parent's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)  * @css: css getting online
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)  * returns 0 in case of success, error code otherwise
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) static int devcgroup_online(struct cgroup_subsys_state *css)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 	struct dev_cgroup *dev_cgroup = css_to_devcgroup(css);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	struct dev_cgroup *parent_dev_cgroup = css_to_devcgroup(css->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 	mutex_lock(&devcgroup_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 	if (parent_dev_cgroup == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 		dev_cgroup->behavior = DEVCG_DEFAULT_ALLOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 		ret = dev_exceptions_copy(&dev_cgroup->exceptions,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 					  &parent_dev_cgroup->exceptions);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 		if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 			dev_cgroup->behavior = parent_dev_cgroup->behavior;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 	mutex_unlock(&devcgroup_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) static void devcgroup_offline(struct cgroup_subsys_state *css)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 	struct dev_cgroup *dev_cgroup = css_to_devcgroup(css);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 	mutex_lock(&devcgroup_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 	dev_cgroup->behavior = DEVCG_DEFAULT_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 	mutex_unlock(&devcgroup_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)  * called from kernel/cgroup.c with cgroup_lock() held.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) static struct cgroup_subsys_state *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) devcgroup_css_alloc(struct cgroup_subsys_state *parent_css)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 	struct dev_cgroup *dev_cgroup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 	dev_cgroup = kzalloc(sizeof(*dev_cgroup), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 	if (!dev_cgroup)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 		return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 	INIT_LIST_HEAD(&dev_cgroup->exceptions);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 	dev_cgroup->behavior = DEVCG_DEFAULT_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 	return &dev_cgroup->css;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) static void devcgroup_css_free(struct cgroup_subsys_state *css)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 	struct dev_cgroup *dev_cgroup = css_to_devcgroup(css);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 	__dev_exception_clean(dev_cgroup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 	kfree(dev_cgroup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) #define DEVCG_ALLOW 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) #define DEVCG_DENY 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) #define DEVCG_LIST 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) #define MAJMINLEN 13
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) #define ACCLEN 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) static void set_access(char *acc, short access)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	int idx = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	memset(acc, 0, ACCLEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 	if (access & DEVCG_ACC_READ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 		acc[idx++] = 'r';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 	if (access & DEVCG_ACC_WRITE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 		acc[idx++] = 'w';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 	if (access & DEVCG_ACC_MKNOD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 		acc[idx++] = 'm';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) static char type_to_char(short type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 	if (type == DEVCG_DEV_ALL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 		return 'a';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	if (type == DEVCG_DEV_CHAR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 		return 'c';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 	if (type == DEVCG_DEV_BLOCK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 		return 'b';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	return 'X';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) static void set_majmin(char *str, unsigned m)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 	if (m == ~0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 		strcpy(str, "*");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 		sprintf(str, "%u", m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) static int devcgroup_seq_show(struct seq_file *m, void *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 	struct dev_cgroup *devcgroup = css_to_devcgroup(seq_css(m));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 	struct dev_exception_item *ex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 	char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 	rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 	 * To preserve the compatibility:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 	 * - Only show the "all devices" when the default policy is to allow
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 	 * - List the exceptions in case the default policy is to deny
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 	 * This way, the file remains as a "whitelist of devices"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 	if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 		set_access(acc, DEVCG_ACC_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 		set_majmin(maj, ~0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 		set_majmin(min, ~0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 		seq_printf(m, "%c %s:%s %s\n", type_to_char(DEVCG_DEV_ALL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 			   maj, min, acc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 		list_for_each_entry_rcu(ex, &devcgroup->exceptions, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 			set_access(acc, ex->access);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 			set_majmin(maj, ex->major);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 			set_majmin(min, ex->minor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 			seq_printf(m, "%c %s:%s %s\n", type_to_char(ex->type),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 				   maj, min, acc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 	rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)  * match_exception	- iterates the exception list trying to find a complete match
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)  * @exceptions: list of exceptions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)  * @type: device type (DEVCG_DEV_BLOCK or DEVCG_DEV_CHAR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)  * @major: device file major number, ~0 to match all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)  * @minor: device file minor number, ~0 to match all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)  * @access: permission mask (DEVCG_ACC_READ, DEVCG_ACC_WRITE, DEVCG_ACC_MKNOD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)  * It is considered a complete match if an exception is found that will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)  * contain the entire range of provided parameters.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)  * Return: true in case it matches an exception completely
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) static bool match_exception(struct list_head *exceptions, short type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 			    u32 major, u32 minor, short access)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 	struct dev_exception_item *ex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 	list_for_each_entry_rcu(ex, exceptions, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 		if ((type & DEVCG_DEV_BLOCK) && !(ex->type & DEVCG_DEV_BLOCK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 		if ((type & DEVCG_DEV_CHAR) && !(ex->type & DEVCG_DEV_CHAR))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 		if (ex->major != ~0 && ex->major != major)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 		if (ex->minor != ~0 && ex->minor != minor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 		/* provided access cannot have more than the exception rule */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 		if (access & (~ex->access))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 		return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 	return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)  * match_exception_partial - iterates the exception list trying to find a partial match
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)  * @exceptions: list of exceptions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)  * @type: device type (DEVCG_DEV_BLOCK or DEVCG_DEV_CHAR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)  * @major: device file major number, ~0 to match all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)  * @minor: device file minor number, ~0 to match all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)  * @access: permission mask (DEVCG_ACC_READ, DEVCG_ACC_WRITE, DEVCG_ACC_MKNOD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)  * It is considered a partial match if an exception's range is found to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)  * contain *any* of the devices specified by provided parameters. This is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)  * used to make sure no extra access is being granted that is forbidden by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)  * any of the exception list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)  * Return: true in case the provided range mat matches an exception completely
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) static bool match_exception_partial(struct list_head *exceptions, short type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 				    u32 major, u32 minor, short access)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 	struct dev_exception_item *ex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 	list_for_each_entry_rcu(ex, exceptions, list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 				lockdep_is_held(&devcgroup_mutex)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 		if ((type & DEVCG_DEV_BLOCK) && !(ex->type & DEVCG_DEV_BLOCK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 		if ((type & DEVCG_DEV_CHAR) && !(ex->type & DEVCG_DEV_CHAR))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 		 * We must be sure that both the exception and the provided
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 		 * range aren't masking all devices
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 		if (ex->major != ~0 && major != ~0 && ex->major != major)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 		if (ex->minor != ~0 && minor != ~0 && ex->minor != minor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 		 * In order to make sure the provided range isn't matching
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 		 * an exception, all its access bits shouldn't match the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 		 * exception's access bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 		if (!(access & ex->access))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 		return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 	return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)  * verify_new_ex - verifies if a new exception is allowed by parent cgroup's permissions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)  * @dev_cgroup: dev cgroup to be tested against
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)  * @refex: new exception
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)  * @behavior: behavior of the exception's dev_cgroup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)  * This is used to make sure a child cgroup won't have more privileges
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)  * than its parent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) static bool verify_new_ex(struct dev_cgroup *dev_cgroup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 		          struct dev_exception_item *refex,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 		          enum devcg_behavior behavior)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 	bool match = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 	RCU_LOCKDEP_WARN(!rcu_read_lock_held() &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 			 !lockdep_is_held(&devcgroup_mutex),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 			 "device_cgroup:verify_new_ex called without proper synchronization");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 	if (dev_cgroup->behavior == DEVCG_DEFAULT_ALLOW) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 		if (behavior == DEVCG_DEFAULT_ALLOW) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 			/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 			 * new exception in the child doesn't matter, only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 			 * adding extra restrictions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 			 */ 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 			return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 			/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 			 * new exception in the child will add more devices
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 			 * that can be acessed, so it can't match any of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 			 * parent's exceptions, even slightly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 			 */ 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 			match = match_exception_partial(&dev_cgroup->exceptions,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 							refex->type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 							refex->major,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 							refex->minor,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 							refex->access);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 			if (match)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 				return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 			return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 		 * Only behavior == DEVCG_DEFAULT_DENY allowed here, therefore
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 		 * the new exception will add access to more devices and must
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 		 * be contained completely in an parent's exception to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 		 * allowed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 		match = match_exception(&dev_cgroup->exceptions, refex->type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 					refex->major, refex->minor,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 					refex->access);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 		if (match)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 			/* parent has an exception that matches the proposed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 			return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 			return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 	return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)  * parent_has_perm:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)  * when adding a new allow rule to a device exception list, the rule
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)  * must be allowed in the parent device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) static int parent_has_perm(struct dev_cgroup *childcg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 				  struct dev_exception_item *ex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 	struct dev_cgroup *parent = css_to_devcgroup(childcg->css.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 	if (!parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 		return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 	return verify_new_ex(parent, ex, childcg->behavior);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)  * parent_allows_removal - verify if it's ok to remove an exception
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)  * @childcg: child cgroup from where the exception will be removed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)  * @ex: exception being removed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)  * When removing an exception in cgroups with default ALLOW policy, it must
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)  * be checked if removing it will give the child cgroup more access than the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)  * parent.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)  * Return: true if it's ok to remove exception, false otherwise
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) static bool parent_allows_removal(struct dev_cgroup *childcg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 				  struct dev_exception_item *ex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 	struct dev_cgroup *parent = css_to_devcgroup(childcg->css.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 	if (!parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 		return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 	/* It's always allowed to remove access to devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 	if (childcg->behavior == DEVCG_DEFAULT_DENY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 		return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 	 * Make sure you're not removing part or a whole exception existing in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 	 * the parent cgroup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 	return !match_exception_partial(&parent->exceptions, ex->type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 					ex->major, ex->minor, ex->access);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)  * may_allow_all - checks if it's possible to change the behavior to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)  *		   allow based on parent's rules.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)  * @parent: device cgroup's parent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)  * returns: != 0 in case it's allowed, 0 otherwise
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) static inline int may_allow_all(struct dev_cgroup *parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 	if (!parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 		return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 	return parent->behavior == DEVCG_DEFAULT_ALLOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505)  * revalidate_active_exceptions - walks through the active exception list and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)  * 				  revalidates the exceptions based on parent's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)  * 				  behavior and exceptions. The exceptions that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)  * 				  are no longer valid will be removed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)  * 				  Called with devcgroup_mutex held.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)  * @devcg: cgroup which exceptions will be checked
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)  * This is one of the three key functions for hierarchy implementation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)  * This function is responsible for re-evaluating all the cgroup's active
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)  * exceptions due to a parent's exception change.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)  * Refer to Documentation/admin-guide/cgroup-v1/devices.rst for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) static void revalidate_active_exceptions(struct dev_cgroup *devcg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 	struct dev_exception_item *ex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) 	struct list_head *this, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) 	list_for_each_safe(this, tmp, &devcg->exceptions) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 		ex = container_of(this, struct dev_exception_item, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) 		if (!parent_has_perm(devcg, ex))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) 			dev_exception_rm(devcg, ex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)  * propagate_exception - propagates a new exception to the children
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)  * @devcg_root: device cgroup that added a new exception
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)  * @ex: new exception to be propagated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)  * returns: 0 in case of success, != 0 in case of error
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) static int propagate_exception(struct dev_cgroup *devcg_root,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) 			       struct dev_exception_item *ex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) 	struct cgroup_subsys_state *pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) 	int rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) 	rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) 	css_for_each_descendant_pre(pos, &devcg_root->css) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) 		struct dev_cgroup *devcg = css_to_devcgroup(pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) 		 * Because devcgroup_mutex is held, no devcg will become
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) 		 * online or offline during the tree walk (see on/offline
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) 		 * methods), and online ones are safe to access outside RCU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) 		 * read lock without bumping refcnt.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) 		if (pos == &devcg_root->css || !is_devcg_online(devcg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) 		rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) 		 * in case both root's behavior and devcg is allow, a new
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) 		 * restriction means adding to the exception list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) 		if (devcg_root->behavior == DEVCG_DEFAULT_ALLOW &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) 		    devcg->behavior == DEVCG_DEFAULT_ALLOW) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) 			rc = dev_exception_add(devcg, ex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) 			if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) 				return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) 			/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) 			 * in the other possible cases:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) 			 * root's behavior: allow, devcg's: deny
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) 			 * root's behavior: deny, devcg's: deny
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) 			 * the exception will be removed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) 			 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) 			dev_exception_rm(devcg, ex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) 		revalidate_active_exceptions(devcg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) 		rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) 	rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) 	return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)  * Modify the exception list using allow/deny rules.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)  * CAP_SYS_ADMIN is needed for this.  It's at least separate from CAP_MKNOD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)  * so we can give a container CAP_MKNOD to let it create devices but not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)  * modify the exception list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)  * It seems likely we'll want to add a CAP_CONTAINER capability to allow
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)  * us to also grant CAP_SYS_ADMIN to containers without giving away the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)  * device exception list controls, but for now we'll stick with CAP_SYS_ADMIN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594)  * Taking rules away is always allowed (given CAP_SYS_ADMIN).  Granting
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)  * new access is only allowed if you're in the top-level cgroup, or your
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596)  * parent cgroup has the access you're asking for.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) static int devcgroup_update_access(struct dev_cgroup *devcgroup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) 				   int filetype, char *buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) 	const char *b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) 	char temp[12];		/* 11 + 1 characters needed for a u32 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) 	int count, rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) 	struct dev_exception_item ex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) 	struct dev_cgroup *parent = css_to_devcgroup(devcgroup->css.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) 	if (!capable(CAP_SYS_ADMIN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) 		return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) 	memset(&ex, 0, sizeof(ex));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) 	b = buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) 	switch (*b) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) 	case 'a':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) 		switch (filetype) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) 		case DEVCG_ALLOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) 			if (css_has_online_children(&devcgroup->css))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) 				return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) 			if (!may_allow_all(parent))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) 				return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) 			dev_exception_clean(devcgroup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) 			devcgroup->behavior = DEVCG_DEFAULT_ALLOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) 			if (!parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) 				break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) 			rc = dev_exceptions_copy(&devcgroup->exceptions,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) 						 &parent->exceptions);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) 			if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) 				return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) 		case DEVCG_DENY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) 			if (css_has_online_children(&devcgroup->css))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) 				return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) 			dev_exception_clean(devcgroup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) 			devcgroup->behavior = DEVCG_DEFAULT_DENY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) 		default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) 	case 'b':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) 		ex.type = DEVCG_DEV_BLOCK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) 	case 'c':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) 		ex.type = DEVCG_DEV_CHAR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) 	b++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) 	if (!isspace(*b))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) 	b++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) 	if (*b == '*') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) 		ex.major = ~0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) 		b++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) 	} else if (isdigit(*b)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) 		memset(temp, 0, sizeof(temp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) 		for (count = 0; count < sizeof(temp) - 1; count++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) 			temp[count] = *b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) 			b++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) 			if (!isdigit(*b))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) 				break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) 		rc = kstrtou32(temp, 10, &ex.major);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) 		if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) 	if (*b != ':')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) 	b++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) 	/* read minor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) 	if (*b == '*') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) 		ex.minor = ~0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) 		b++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) 	} else if (isdigit(*b)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) 		memset(temp, 0, sizeof(temp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) 		for (count = 0; count < sizeof(temp) - 1; count++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) 			temp[count] = *b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) 			b++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) 			if (!isdigit(*b))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) 				break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) 		rc = kstrtou32(temp, 10, &ex.minor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) 		if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) 	if (!isspace(*b))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) 	for (b++, count = 0; count < 3; count++, b++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) 		switch (*b) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) 		case 'r':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) 			ex.access |= DEVCG_ACC_READ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) 		case 'w':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) 			ex.access |= DEVCG_ACC_WRITE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) 		case 'm':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) 			ex.access |= DEVCG_ACC_MKNOD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) 		case '\n':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) 		case '\0':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) 			count = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) 		default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) 	switch (filetype) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) 	case DEVCG_ALLOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) 		 * If the default policy is to allow by default, try to remove
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) 		 * an matching exception instead. And be silent about it: we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) 		 * don't want to break compatibility
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) 		if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) 			/* Check if the parent allows removing it first */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) 			if (!parent_allows_removal(devcgroup, &ex))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) 				return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) 			dev_exception_rm(devcgroup, &ex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) 		if (!parent_has_perm(devcgroup, &ex))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) 			return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) 		rc = dev_exception_add(devcgroup, &ex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) 	case DEVCG_DENY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) 		 * If the default policy is to deny by default, try to remove
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) 		 * an matching exception instead. And be silent about it: we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) 		 * don't want to break compatibility
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) 		if (devcgroup->behavior == DEVCG_DEFAULT_DENY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) 			dev_exception_rm(devcgroup, &ex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) 			rc = dev_exception_add(devcgroup, &ex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) 		if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) 		/* we only propagate new restrictions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) 		rc = propagate_exception(devcgroup, &ex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) 		rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) 	return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) static ssize_t devcgroup_access_write(struct kernfs_open_file *of,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) 				      char *buf, size_t nbytes, loff_t off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) 	int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) 	mutex_lock(&devcgroup_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) 	retval = devcgroup_update_access(css_to_devcgroup(of_css(of)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) 					 of_cft(of)->private, strstrip(buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) 	mutex_unlock(&devcgroup_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) 	return retval ?: nbytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) static struct cftype dev_cgroup_files[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) 		.name = "allow",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) 		.write = devcgroup_access_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) 		.private = DEVCG_ALLOW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) 		.name = "deny",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) 		.write = devcgroup_access_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) 		.private = DEVCG_DENY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) 		.name = "list",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) 		.seq_show = devcgroup_seq_show,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) 		.private = DEVCG_LIST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) 	{ }	/* terminate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) struct cgroup_subsys devices_cgrp_subsys = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) 	.css_alloc = devcgroup_css_alloc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) 	.css_free = devcgroup_css_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) 	.css_online = devcgroup_online,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) 	.css_offline = devcgroup_offline,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) 	.legacy_cftypes = dev_cgroup_files,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798)  * devcgroup_legacy_check_permission - checks if an inode operation is permitted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799)  * @dev_cgroup: the dev cgroup to be tested against
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800)  * @type: device type
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801)  * @major: device major number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802)  * @minor: device minor number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803)  * @access: combination of DEVCG_ACC_WRITE, DEVCG_ACC_READ and DEVCG_ACC_MKNOD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805)  * returns 0 on success, -EPERM case the operation is not permitted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) static int devcgroup_legacy_check_permission(short type, u32 major, u32 minor,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) 					short access)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) 	struct dev_cgroup *dev_cgroup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) 	bool rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) 	rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) 	dev_cgroup = task_devcgroup(current);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) 	if (dev_cgroup->behavior == DEVCG_DEFAULT_ALLOW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) 		/* Can't match any of the exceptions, even partially */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) 		rc = !match_exception_partial(&dev_cgroup->exceptions,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) 					      type, major, minor, access);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) 		/* Need to match completely one exception to be allowed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) 		rc = match_exception(&dev_cgroup->exceptions, type, major,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) 				     minor, access);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) 	rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) 	if (!rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) 		return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) #endif /* CONFIG_CGROUP_DEVICE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) #if defined(CONFIG_CGROUP_DEVICE) || defined(CONFIG_CGROUP_BPF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) int devcgroup_check_permission(short type, u32 major, u32 minor, short access)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) 	int rc = BPF_CGROUP_RUN_PROG_DEVICE_CGROUP(type, major, minor, access);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) 	if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) 		return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) 	#ifdef CONFIG_CGROUP_DEVICE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) 	return devcgroup_legacy_check_permission(type, major, minor, access);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) 	#else /* CONFIG_CGROUP_DEVICE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) 	#endif /* CONFIG_CGROUP_DEVICE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) EXPORT_SYMBOL(devcgroup_check_permission);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) #endif /* defined(CONFIG_CGROUP_DEVICE) || defined(CONFIG_CGROUP_BPF) */