~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/security/device_cgroup.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /security/device_cgroup.c (Version linux-6.11.5) and /security/device_cgroup.c (Version linux-3.10.108)


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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php