diff options
author | Serge E. Hallyn <serue@us.ibm.com> | 2008-04-29 04:00:14 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-29 11:06:10 -0400 |
commit | 29486df325e1fe6e1764afcb19e3370804c2b002 (patch) | |
tree | d69a96bb829940f3ae5171fde481edb20a9e468a /security | |
parent | 28fd5dfc12bde391981dfdcf20755952b6e916af (diff) |
cgroups: introduce cft->read_seq()
Introduce a read_seq() helper in cftype, which uses seq_file to print out
lists. Use it in the devices cgroup. Also split devices.allow into two
files, so now devices.deny and devices.allow are the ones to use to manipulate
the whitelist, while devices.list outputs the cgroup's current whitelist.
Signed-off-by: Serge E. Hallyn <serue@us.ibm.com>
Acked-by: Paul Menage <menage@google.com>
Cc: Balbir Singh <balbir@in.ibm.com>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'security')
-rw-r--r-- | security/device_cgroup.c | 74 |
1 files changed, 23 insertions, 51 deletions
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 | ||
205 | static void set_access(char *acc, short access) | 210 | static 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 | ||
228 | static void set_majmin(char *str, int len, unsigned m) | 233 | static 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 | ||
237 | static char *print_whitelist(struct dev_cgroup *devcgroup, int *len) | 242 | static 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 | |||
273 | static 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: | |||
501 | static struct cftype dev_cgroup_files[] = { | 469 | static 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 | ||
515 | static int devcgroup_populate(struct cgroup_subsys *ss, | 487 | static int devcgroup_populate(struct cgroup_subsys *ss, |