Commit d591fb56618f4f93160b477dfa25bbb1e31b0e85

Authored by Tejun Heo
1 parent 75501a6d59

device_cgroup: simplify cgroup tree walk in propagate_exception()

During a config change, propagate_exception() needs to traverse the
subtree to update config on the subtree.  Because such config updates
need to allocate memory, it couldn't directly use
cgroup_for_each_descendant_pre() which required the whole iteration to
be contained in a single RCU read critical section.  To work around
the limitation, propagate_exception() built a linked list of
descendant cgroups while read-locking RCU and then walked the list
afterwards, which is safe as the whole iteration is protected by
devcgroup_mutex.  This works but is cumbersome.

With the recent updates, cgroup iterators now allow dropping RCU read
lock while iteration is in progress making this workaround no longer
necessary.  This patch replaces dev_cgroup->propagate_pending list and
get_online_devcg() with direct cgroup_for_each_descendant_pre() walk.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Aristeu Rozanski <aris@redhat.com>
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
Reviewed-by: Michal Hocko <mhocko@suse.cz>

Showing 1 changed file with 18 additions and 38 deletions Inline Diff

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