aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--security/device_cgroup.c56
1 files changed, 18 insertions, 38 deletions
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index dd0dc574d78d..e8aad69f0d69 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -49,8 +49,6 @@ 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
56static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s) 54static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s)
@@ -241,7 +239,6 @@ static struct cgroup_subsys_state *devcgroup_css_alloc(struct cgroup *cgroup)
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;
@@ -445,34 +442,6 @@ static void revalidate_active_exceptions(struct dev_cgroup *devcg)
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 */
459static 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
@@ -482,15 +451,24 @@ static void get_online_devcg(struct cgroup *root, struct list_head *online)
482static int propagate_exception(struct dev_cgroup *devcg_root, 451static 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);
461
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();
494 472
495 /* 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
@@ -512,8 +490,10 @@ static int propagate_exception(struct dev_cgroup *devcg_root,
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