Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756608Ab2K0Uct (ORCPT ); Tue, 27 Nov 2012 15:32:49 -0500 Received: from mx1.redhat.com ([209.132.183.28]:21094 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755381Ab2K0Ucr (ORCPT ); Tue, 27 Nov 2012 15:32:47 -0500 Message-Id: <20121127193502.482004744@napanee.usersys.redhat.com> User-Agent: quilt/0.48-1 Date: Tue, 27 Nov 2012 14:35:04 -0500 From: Aristeu Rozanski To: linux-kernel@vger.kernel.org Cc: Tejun Heo , Serge Hallyn , cgroups@vger.kernel.org Subject: [PATCH 3/5] device_cgroup: keep track of local group settings References: <20121127193501.255267751@napanee.usersys.redhat.com> Content-Disposition: inline; filename=hierarchy.patch Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5448 Lines: 206 In preparation for better hierarchy support, it's needed to retain the local settings in order to try to reapply them after a propagated change if they're still valid. Cc: Tejun Heo Cc: Serge Hallyn Signed-off-by: Aristeu Rozanski --- security/device_cgroup.c | 108 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 80 insertions(+), 28 deletions(-) Index: github/security/device_cgroup.c =================================================================== --- github.orig/security/device_cgroup.c 2012-11-26 17:27:52.710834676 -0500 +++ github/security/device_cgroup.c 2012-11-27 11:58:09.333349468 -0500 @@ -39,13 +39,27 @@ struct rcu_head rcu; }; +enum devcg_behavior { + DEVCG_DEFAULT_NONE, + DEVCG_DEFAULT_ALLOW, + DEVCG_DEFAULT_DENY, +}; + struct dev_cgroup { struct cgroup_subsys_state css; + + /* result of merging the parent's rules with local ones */ struct list_head exceptions; - enum { - DEVCG_DEFAULT_ALLOW, - DEVCG_DEFAULT_DENY, - } behavior; + enum devcg_behavior behavior; + + /* + * local set rules, saved so when a parent propagates new rules, the + * local preferences can be preserved + */ + struct { + struct list_head exceptions; + enum devcg_behavior behavior; + } local; }; static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s) @@ -104,8 +118,41 @@ /* * called under devcgroup_mutex */ -static int dev_exception_add(struct list_head *exceptions, - struct dev_exception_item *ex) +static void __dev_exception_rm(struct list_head *exceptions, + struct dev_exception_item *ex) +{ + struct dev_exception_item *walk, *tmp; + + lockdep_assert_held(&devcgroup_mutex); + + list_for_each_entry_safe(walk, tmp, exceptions, list) { + if (walk->type != ex->type) + continue; + if (walk->major != ex->major) + continue; + if (walk->minor != ex->minor) + continue; + + walk->access &= ~ex->access; + if (!walk->access) { + list_del_rcu(&walk->list); + kfree_rcu(walk, rcu); + } + } +} + +static void dev_exception_rm(struct dev_cgroup *devcgroup, + struct dev_exception_item *ex) +{ + __dev_exception_rm(&devcgroup->local.exceptions, ex); + __dev_exception_rm(&devcgroup->exceptions, ex); +} + +/* + * called under devcgroup_mutex + */ +static int __dev_exception_add(struct list_head *exceptions, + struct dev_exception_item *ex) { struct dev_exception_item *excopy, *walk; @@ -133,30 +180,26 @@ return 0; } -/* - * called under devcgroup_mutex - */ -static void dev_exception_rm(struct list_head *exceptions, +static int dev_exception_add(struct dev_cgroup *devcgroup, struct dev_exception_item *ex) { - struct dev_exception_item *walk, *tmp; + int rc; lockdep_assert_held(&devcgroup_mutex); - list_for_each_entry_safe(walk, tmp, exceptions, list) { - if (walk->type != ex->type) - continue; - if (walk->major != ex->major) - continue; - if (walk->minor != ex->minor) - continue; + /* + * we add to the local list so we can preserve local preferences if + * the parent propagates down new rules + */ + rc = __dev_exception_add(&devcgroup->local.exceptions, ex); + if (rc) + return rc; + + rc = __dev_exception_add(&devcgroup->exceptions, ex); + if (rc) + __dev_exception_rm(&devcgroup->local.exceptions, ex); - walk->access &= ~ex->access; - if (!walk->access) { - list_del_rcu(&walk->list); - kfree_rcu(walk, rcu); - } - } + return rc; } /** @@ -175,6 +218,11 @@ list_del_rcu(&ex->list); kfree_rcu(ex, rcu); } + list_for_each_entry_safe(ex, tmp, &dev_cgroup->local.exceptions, + list) { + list_del_rcu(&ex->list); + kfree_rcu(ex, rcu); + } } /* @@ -190,6 +238,8 @@ if (!dev_cgroup) return ERR_PTR(-ENOMEM); INIT_LIST_HEAD(&dev_cgroup->exceptions); + INIT_LIST_HEAD(&dev_cgroup->local.exceptions); + dev_cgroup->local.behavior = DEVCG_DEFAULT_NONE; parent_cgroup = cgroup->parent; if (parent_cgroup == NULL) @@ -413,6 +463,7 @@ return -EPERM; dev_exception_clean(devcgroup); devcgroup->behavior = DEVCG_DEFAULT_ALLOW; + devcgroup->local.behavior = DEVCG_DEFAULT_ALLOW; if (!parent) break; @@ -424,6 +475,7 @@ case DEVCG_DENY: dev_exception_clean(devcgroup); devcgroup->behavior = DEVCG_DEFAULT_DENY; + devcgroup->local.behavior = DEVCG_DEFAULT_DENY; break; default: return -EINVAL; @@ -513,10 +565,10 @@ * don't want to break compatibility */ if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) { - dev_exception_rm(&devcgroup->exceptions, &ex); + dev_exception_rm(devcgroup, &ex); return 0; } - return dev_exception_add(&devcgroup->exceptions, &ex); + return dev_exception_add(devcgroup, &ex); case DEVCG_DENY: /* * If the default policy is to deny by default, try to remove @@ -524,10 +576,10 @@ * don't want to break compatibility */ if (devcgroup->behavior == DEVCG_DEFAULT_DENY) { - dev_exception_rm(&devcgroup->exceptions, &ex); + dev_exception_rm(devcgroup, &ex); return 0; } - return dev_exception_add(&devcgroup->exceptions, &ex); + return dev_exception_add(devcgroup, &ex); default: return -EINVAL; } -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/