aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/cgroup.h6
-rw-r--r--kernel/cgroup.c15
-rw-r--r--security/device_cgroup.c74
3 files changed, 38 insertions, 57 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index d58a958444ab..095248082b7e 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -226,6 +226,12 @@ struct cftype {
226 */ 226 */
227 int (*read_map) (struct cgroup *cont, struct cftype *cft, 227 int (*read_map) (struct cgroup *cont, struct cftype *cft,
228 struct cgroup_map_cb *cb); 228 struct cgroup_map_cb *cb);
229 /*
230 * read_seq_string() is used for outputting a simple sequence
231 * using seqfile.
232 */
233 int (*read_seq_string) (struct cgroup *cont, struct cftype *cft,
234 struct seq_file *m);
229 235
230 ssize_t (*write) (struct cgroup *cgrp, struct cftype *cft, 236 ssize_t (*write) (struct cgroup *cgrp, struct cftype *cft,
231 struct file *file, 237 struct file *file,
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index aeceb8868981..abc433772e5a 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -1549,11 +1549,14 @@ static int cgroup_seqfile_show(struct seq_file *m, void *arg)
1549{ 1549{
1550 struct cgroup_seqfile_state *state = m->private; 1550 struct cgroup_seqfile_state *state = m->private;
1551 struct cftype *cft = state->cft; 1551 struct cftype *cft = state->cft;
1552 struct cgroup_map_cb cb = { 1552 if (cft->read_map) {
1553 .fill = cgroup_map_add, 1553 struct cgroup_map_cb cb = {
1554 .state = m, 1554 .fill = cgroup_map_add,
1555 }; 1555 .state = m,
1556 return cft->read_map(state->cgroup, cft, &cb); 1556 };
1557 return cft->read_map(state->cgroup, cft, &cb);
1558 }
1559 return cft->read_seq_string(state->cgroup, cft, m);
1557} 1560}
1558 1561
1559int cgroup_seqfile_release(struct inode *inode, struct file *file) 1562int cgroup_seqfile_release(struct inode *inode, struct file *file)
@@ -1581,7 +1584,7 @@ static int cgroup_file_open(struct inode *inode, struct file *file)
1581 cft = __d_cft(file->f_dentry); 1584 cft = __d_cft(file->f_dentry);
1582 if (!cft) 1585 if (!cft)
1583 return -ENODEV; 1586 return -ENODEV;
1584 if (cft->read_map) { 1587 if (cft->read_map || cft->read_seq_string) {
1585 struct cgroup_seqfile_state *state = 1588 struct cgroup_seqfile_state *state =
1586 kzalloc(sizeof(*state), GFP_USER); 1589 kzalloc(sizeof(*state), GFP_USER);
1587 if (!state) 1590 if (!state)
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index 4237b19e8fb3..4ea583689eec 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -9,6 +9,7 @@
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 13
13#define ACC_MKNOD 1 14#define ACC_MKNOD 1
14#define ACC_READ 2 15#define ACC_READ 2
@@ -201,11 +202,15 @@ static void devcgroup_destroy(struct cgroup_subsys *ss,
201 202
202#define DEVCG_ALLOW 1 203#define DEVCG_ALLOW 1
203#define DEVCG_DENY 2 204#define DEVCG_DENY 2
205#define DEVCG_LIST 3
206
207#define MAJMINLEN 10
208#define ACCLEN 4
204 209
205static void set_access(char *acc, short access) 210static void set_access(char *acc, short access)
206{ 211{
207 int idx = 0; 212 int idx = 0;
208 memset(acc, 0, 4); 213 memset(acc, 0, ACCLEN);
209 if (access & ACC_READ) 214 if (access & ACC_READ)
210 acc[idx++] = 'r'; 215 acc[idx++] = 'r';
211 if (access & ACC_WRITE) 216 if (access & ACC_WRITE)
@@ -225,70 +230,33 @@ static char type_to_char(short type)
225 return 'X'; 230 return 'X';
226} 231}
227 232
228static void set_majmin(char *str, int len, unsigned m) 233static void set_majmin(char *str, unsigned m)
229{ 234{
230 memset(str, 0, len); 235 memset(str, 0, MAJMINLEN);
231 if (m == ~0) 236 if (m == ~0)
232 sprintf(str, "*"); 237 sprintf(str, "*");
233 else 238 else
234 snprintf(str, len, "%d", m); 239 snprintf(str, MAJMINLEN, "%d", m);
235} 240}
236 241
237static char *print_whitelist(struct dev_cgroup *devcgroup, int *len) 242static int devcgroup_seq_read(struct cgroup *cgroup, struct cftype *cft,
243 struct seq_file *m)
238{ 244{
239 char *buf, *s, acc[4]; 245 struct dev_cgroup *devcgroup = cgroup_to_devcgroup(cgroup);
240 struct dev_whitelist_item *wh; 246 struct dev_whitelist_item *wh;
241 int ret; 247 char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN];
242 int count = 0;
243 char maj[10], min[10];
244
245 buf = kmalloc(4096, GFP_KERNEL);
246 if (!buf)
247 return ERR_PTR(-ENOMEM);
248 s = buf;
249 *s = '\0';
250 *len = 0;
251 248
252 spin_lock(&devcgroup->lock); 249 spin_lock(&devcgroup->lock);
253 list_for_each_entry(wh, &devcgroup->whitelist, list) { 250 list_for_each_entry(wh, &devcgroup->whitelist, list) {
254 set_access(acc, wh->access); 251 set_access(acc, wh->access);
255 set_majmin(maj, 10, wh->major); 252 set_majmin(maj, wh->major);
256 set_majmin(min, 10, wh->minor); 253 set_majmin(min, wh->minor);
257 ret = snprintf(s, 4095-(s-buf), "%c %s:%s %s\n", 254 seq_printf(m, "%c %s:%s %s\n", type_to_char(wh->type),
258 type_to_char(wh->type), maj, min, acc); 255 maj, min, acc);
259 if (s+ret >= buf+4095) {
260 kfree(buf);
261 buf = ERR_PTR(-ENOMEM);
262 break;
263 }
264 s += ret;
265 *len += ret;
266 count++;
267 } 256 }
268 spin_unlock(&devcgroup->lock); 257 spin_unlock(&devcgroup->lock);
269 258
270 return buf; 259 return 0;
271}
272
273static ssize_t devcgroup_access_read(struct cgroup *cgroup,
274 struct cftype *cft, struct file *file,
275 char __user *userbuf, size_t nbytes, loff_t *ppos)
276{
277 struct dev_cgroup *devcgroup = cgroup_to_devcgroup(cgroup);
278 int filetype = cft->private;
279 char *buffer;
280 int uninitialized_var(len);
281 int retval;
282
283 if (filetype != DEVCG_ALLOW)
284 return -EINVAL;
285 buffer = print_whitelist(devcgroup, &len);
286 if (IS_ERR(buffer))
287 return PTR_ERR(buffer);
288
289 retval = simple_read_from_buffer(userbuf, nbytes, ppos, buffer, len);
290 kfree(buffer);
291 return retval;
292} 260}
293 261
294/* 262/*
@@ -501,7 +469,6 @@ out1:
501static struct cftype dev_cgroup_files[] = { 469static struct cftype dev_cgroup_files[] = {
502 { 470 {
503 .name = "allow", 471 .name = "allow",
504 .read = devcgroup_access_read,
505 .write = devcgroup_access_write, 472 .write = devcgroup_access_write,
506 .private = DEVCG_ALLOW, 473 .private = DEVCG_ALLOW,
507 }, 474 },
@@ -510,6 +477,11 @@ static struct cftype dev_cgroup_files[] = {
510 .write = devcgroup_access_write, 477 .write = devcgroup_access_write,
511 .private = DEVCG_DENY, 478 .private = DEVCG_DENY,
512 }, 479 },
480 {
481 .name = "list",
482 .read_seq_string = devcgroup_seq_read,
483 .private = DEVCG_LIST,
484 },
513}; 485};
514 486
515static int devcgroup_populate(struct cgroup_subsys *ss, 487static int devcgroup_populate(struct cgroup_subsys *ss,