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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.