aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--security/device_cgroup.c34
1 files changed, 5 insertions, 29 deletions
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index d5c15a7c67c3..5ba78701adc3 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * dev_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 */
@@ -10,6 +10,7 @@
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/rcupdate.h>
13 14
14#define ACC_MKNOD 1 15#define ACC_MKNOD 1
15#define ACC_READ 2 16#define ACC_READ 2
@@ -22,18 +23,8 @@
22 23
23/* 24/*
24 * whitelist locking rules: 25 * whitelist locking rules:
25 * cgroup_lock() cannot be taken under dev_cgroup->lock. 26 * hold cgroup_lock() for update/read.
26 * dev_cgroup->lock can be taken with or without cgroup_lock(). 27 * hold rcu_read_lock() for read.
27 *
28 * modifications always require cgroup_lock
29 * modifications to a list which is visible require the
30 * dev_cgroup->lock *and* cgroup_lock()
31 * walking the list requires dev_cgroup->lock or cgroup_lock().
32 *
33 * reasoning: dev_whitelist_copy() needs to kmalloc, so needs
34 * a mutex, which the cgroup_lock() is. Since modifying
35 * a visible list requires both locks, either lock can be
36 * taken for walking the list.
37 */ 28 */
38 29
39struct dev_whitelist_item { 30struct dev_whitelist_item {
@@ -47,7 +38,6 @@ struct dev_whitelist_item {
47struct dev_cgroup { 38struct dev_cgroup {
48 struct cgroup_subsys_state css; 39 struct cgroup_subsys_state css;
49 struct list_head whitelist; 40 struct list_head whitelist;
50 spinlock_t lock;
51}; 41};
52 42
53static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s) 43static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s)
@@ -103,7 +93,6 @@ free_and_exit:
103/* Stupid prototype - don't bother combining existing entries */ 93/* Stupid prototype - don't bother combining existing entries */
104/* 94/*
105 * called under cgroup_lock() 95 * called under cgroup_lock()
106 * since the list is visible to other tasks, we need the spinlock also
107 */ 96 */
108static int dev_whitelist_add(struct dev_cgroup *dev_cgroup, 97static int dev_whitelist_add(struct dev_cgroup *dev_cgroup,
109 struct dev_whitelist_item *wh) 98 struct dev_whitelist_item *wh)
@@ -114,7 +103,6 @@ static int dev_whitelist_add(struct dev_cgroup *dev_cgroup,
114 if (!whcopy) 103 if (!whcopy)
115 return -ENOMEM; 104 return -ENOMEM;
116 105
117 spin_lock(&dev_cgroup->lock);
118 list_for_each_entry(walk, &dev_cgroup->whitelist, list) { 106 list_for_each_entry(walk, &dev_cgroup->whitelist, list) {
119 if (walk->type != wh->type) 107 if (walk->type != wh->type)
120 continue; 108 continue;
@@ -130,7 +118,6 @@ static int dev_whitelist_add(struct dev_cgroup *dev_cgroup,
130 118
131 if (whcopy != NULL) 119 if (whcopy != NULL)
132 list_add_tail_rcu(&whcopy->list, &dev_cgroup->whitelist); 120 list_add_tail_rcu(&whcopy->list, &dev_cgroup->whitelist);
133 spin_unlock(&dev_cgroup->lock);
134 return 0; 121 return 0;
135} 122}
136 123
@@ -144,14 +131,12 @@ static void whitelist_item_free(struct rcu_head *rcu)
144 131
145/* 132/*
146 * called under cgroup_lock() 133 * called under cgroup_lock()
147 * since the list is visible to other tasks, we need the spinlock also
148 */ 134 */
149static void dev_whitelist_rm(struct dev_cgroup *dev_cgroup, 135static void dev_whitelist_rm(struct dev_cgroup *dev_cgroup,
150 struct dev_whitelist_item *wh) 136 struct dev_whitelist_item *wh)
151{ 137{
152 struct dev_whitelist_item *walk, *tmp; 138 struct dev_whitelist_item *walk, *tmp;
153 139
154 spin_lock(&dev_cgroup->lock);
155 list_for_each_entry_safe(walk, tmp, &dev_cgroup->whitelist, list) { 140 list_for_each_entry_safe(walk, tmp, &dev_cgroup->whitelist, list) {
156 if (walk->type == DEV_ALL) 141 if (walk->type == DEV_ALL)
157 goto remove; 142 goto remove;
@@ -169,7 +154,6 @@ remove:
169 call_rcu(&walk->rcu, whitelist_item_free); 154 call_rcu(&walk->rcu, whitelist_item_free);
170 } 155 }
171 } 156 }
172 spin_unlock(&dev_cgroup->lock);
173} 157}
174 158
175/* 159/*
@@ -209,7 +193,6 @@ static struct cgroup_subsys_state *devcgroup_create(struct cgroup_subsys *ss,
209 } 193 }
210 } 194 }
211 195
212 spin_lock_init(&dev_cgroup->lock);
213 return &dev_cgroup->css; 196 return &dev_cgroup->css;
214} 197}
215 198
@@ -325,15 +308,11 @@ static int parent_has_perm(struct dev_cgroup *childcg,
325{ 308{
326 struct cgroup *pcg = childcg->css.cgroup->parent; 309 struct cgroup *pcg = childcg->css.cgroup->parent;
327 struct dev_cgroup *parent; 310 struct dev_cgroup *parent;
328 int ret;
329 311
330 if (!pcg) 312 if (!pcg)
331 return 1; 313 return 1;
332 parent = cgroup_to_devcgroup(pcg); 314 parent = cgroup_to_devcgroup(pcg);
333 spin_lock(&parent->lock); 315 return may_access_whitelist(parent, wh);
334 ret = may_access_whitelist(parent, wh);
335 spin_unlock(&parent->lock);
336 return ret;
337} 316}
338 317
339/* 318/*
@@ -352,7 +331,6 @@ static int parent_has_perm(struct dev_cgroup *childcg,
352static int devcgroup_update_access(struct dev_cgroup *devcgroup, 331static int devcgroup_update_access(struct dev_cgroup *devcgroup,
353 int filetype, const char *buffer) 332 int filetype, const char *buffer)
354{ 333{
355 struct dev_cgroup *cur_devcgroup;
356 const char *b; 334 const char *b;
357 char *endp; 335 char *endp;
358 int count; 336 int count;
@@ -361,8 +339,6 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
361 if (!capable(CAP_SYS_ADMIN)) 339 if (!capable(CAP_SYS_ADMIN))
362 return -EPERM; 340 return -EPERM;
363 341
364 cur_devcgroup = task_devcgroup(current);
365
366 memset(&wh, 0, sizeof(wh)); 342 memset(&wh, 0, sizeof(wh));
367 b = buffer; 343 b = buffer;
368 344