aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorPaul Menage <menage@google.com>2008-07-25 04:47:03 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-25 13:53:36 -0400
commitf92523e3a7861f5dbd76021e0719a35fe8771f2d (patch)
tree933c9e6e1f0683ac1c6bc019da5b91c9e567bf7c /security
parente37123953292146445c8629b3950d0513fd10ae2 (diff)
cgroup files: convert devcgroup_access_write() into a cgroup write_string() handler
This patch converts devcgroup_access_write() from a raw file handler into a handler for the cgroup write_string() method. This allows some boilerplate copying/locking/checking to be removed and simplifies the cleanup path, since these functions are performed by the cgroups framework before calling the handler. Signed-off-by: Paul Menage <menage@google.com> Cc: Paul Jackson <pj@sgi.com> Cc: Pavel Emelyanov <xemul@openvz.org> Cc: Balbir Singh <balbir@in.ibm.com> Acked-by: Serge Hallyn <serue@us.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.c101
1 files changed, 38 insertions, 63 deletions
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index ddd92cec78ed..236fffa9d05e 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -59,6 +59,11 @@ static inline struct dev_cgroup *cgroup_to_devcgroup(struct cgroup *cgroup)
59 return css_to_devcgroup(cgroup_subsys_state(cgroup, devices_subsys_id)); 59 return css_to_devcgroup(cgroup_subsys_state(cgroup, devices_subsys_id));
60} 60}
61 61
62static inline struct dev_cgroup *task_devcgroup(struct task_struct *task)
63{
64 return css_to_devcgroup(task_subsys_state(task, devices_subsys_id));
65}
66
62struct cgroup_subsys devices_subsys; 67struct cgroup_subsys devices_subsys;
63 68
64static int devcgroup_can_attach(struct cgroup_subsys *ss, 69static int devcgroup_can_attach(struct cgroup_subsys *ss,
@@ -312,10 +317,10 @@ static int may_access_whitelist(struct dev_cgroup *c,
312 * when adding a new allow rule to a device whitelist, the rule 317 * when adding a new allow rule to a device whitelist, the rule
313 * must be allowed in the parent device 318 * must be allowed in the parent device
314 */ 319 */
315static int parent_has_perm(struct cgroup *childcg, 320static int parent_has_perm(struct dev_cgroup *childcg,
316 struct dev_whitelist_item *wh) 321 struct dev_whitelist_item *wh)
317{ 322{
318 struct cgroup *pcg = childcg->parent; 323 struct cgroup *pcg = childcg->css.cgroup->parent;
319 struct dev_cgroup *parent; 324 struct dev_cgroup *parent;
320 int ret; 325 int ret;
321 326
@@ -341,39 +346,18 @@ static int parent_has_perm(struct cgroup *childcg,
341 * new access is only allowed if you're in the top-level cgroup, or your 346 * new access is only allowed if you're in the top-level cgroup, or your
342 * parent cgroup has the access you're asking for. 347 * parent cgroup has the access you're asking for.
343 */ 348 */
344static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft, 349static int devcgroup_update_access(struct dev_cgroup *devcgroup,
345 struct file *file, const char __user *userbuf, 350 int filetype, const char *buffer)
346 size_t nbytes, loff_t *ppos)
347{ 351{
348 struct cgroup *cur_cgroup; 352 struct dev_cgroup *cur_devcgroup;
349 struct dev_cgroup *devcgroup, *cur_devcgroup; 353 const char *b;
350 int filetype = cft->private;
351 char *buffer, *b;
352 int retval = 0, count; 354 int retval = 0, count;
353 struct dev_whitelist_item wh; 355 struct dev_whitelist_item wh;
354 356
355 if (!capable(CAP_SYS_ADMIN)) 357 if (!capable(CAP_SYS_ADMIN))
356 return -EPERM; 358 return -EPERM;
357 359
358 devcgroup = cgroup_to_devcgroup(cgroup); 360 cur_devcgroup = task_devcgroup(current);
359 cur_cgroup = task_cgroup(current, devices_subsys.subsys_id);
360 cur_devcgroup = cgroup_to_devcgroup(cur_cgroup);
361
362 buffer = kmalloc(nbytes+1, GFP_KERNEL);
363 if (!buffer)
364 return -ENOMEM;
365
366 if (copy_from_user(buffer, userbuf, nbytes)) {
367 retval = -EFAULT;
368 goto out1;
369 }
370 buffer[nbytes] = 0; /* nul-terminate */
371
372 cgroup_lock();
373 if (cgroup_is_removed(cgroup)) {
374 retval = -ENODEV;
375 goto out2;
376 }
377 361
378 memset(&wh, 0, sizeof(wh)); 362 memset(&wh, 0, sizeof(wh));
379 b = buffer; 363 b = buffer;
@@ -392,14 +376,11 @@ static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft,
392 wh.type = DEV_CHAR; 376 wh.type = DEV_CHAR;
393 break; 377 break;
394 default: 378 default:
395 retval = -EINVAL; 379 return -EINVAL;
396 goto out2;
397 } 380 }
398 b++; 381 b++;
399 if (!isspace(*b)) { 382 if (!isspace(*b))
400 retval = -EINVAL; 383 return -EINVAL;
401 goto out2;
402 }
403 b++; 384 b++;
404 if (*b == '*') { 385 if (*b == '*') {
405 wh.major = ~0; 386 wh.major = ~0;
@@ -411,13 +392,10 @@ static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft,
411 b++; 392 b++;
412 } 393 }
413 } else { 394 } else {
414 retval = -EINVAL; 395 return -EINVAL;
415 goto out2;
416 }
417 if (*b != ':') {
418 retval = -EINVAL;
419 goto out2;
420 } 396 }
397 if (*b != ':')
398 return -EINVAL;
421 b++; 399 b++;
422 400
423 /* read minor */ 401 /* read minor */
@@ -431,13 +409,10 @@ static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft,
431 b++; 409 b++;
432 } 410 }
433 } else { 411 } else {
434 retval = -EINVAL; 412 return -EINVAL;
435 goto out2;
436 }
437 if (!isspace(*b)) {
438 retval = -EINVAL;
439 goto out2;
440 } 413 }
414 if (!isspace(*b))
415 return -EINVAL;
441 for (b++, count = 0; count < 3; count++, b++) { 416 for (b++, count = 0; count < 3; count++, b++) {
442 switch (*b) { 417 switch (*b) {
443 case 'r': 418 case 'r':
@@ -454,8 +429,7 @@ static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft,
454 count = 3; 429 count = 3;
455 break; 430 break;
456 default: 431 default:
457 retval = -EINVAL; 432 return -EINVAL;
458 goto out2;
459 } 433 }
460 } 434 }
461 435
@@ -463,38 +437,39 @@ handle:
463 retval = 0; 437 retval = 0;
464 switch (filetype) { 438 switch (filetype) {
465 case DEVCG_ALLOW: 439 case DEVCG_ALLOW:
466 if (!parent_has_perm(cgroup, &wh)) 440 if (!parent_has_perm(devcgroup, &wh))
467 retval = -EPERM; 441 return -EPERM;
468 else 442 return dev_whitelist_add(devcgroup, &wh);
469 retval = dev_whitelist_add(devcgroup, &wh);
470 break;
471 case DEVCG_DENY: 443 case DEVCG_DENY:
472 dev_whitelist_rm(devcgroup, &wh); 444 dev_whitelist_rm(devcgroup, &wh);
473 break; 445 break;
474 default: 446 default:
475 retval = -EINVAL; 447 return -EINVAL;
476 goto out2;
477 } 448 }
449 return 0;
450}
478 451
479 if (retval == 0) 452static int devcgroup_access_write(struct cgroup *cgrp, struct cftype *cft,
480 retval = nbytes; 453 const char *buffer)
481 454{
482out2: 455 int retval;
456 if (!cgroup_lock_live_group(cgrp))
457 return -ENODEV;
458 retval = devcgroup_update_access(cgroup_to_devcgroup(cgrp),
459 cft->private, buffer);
483 cgroup_unlock(); 460 cgroup_unlock();
484out1:
485 kfree(buffer);
486 return retval; 461 return retval;
487} 462}
488 463
489static struct cftype dev_cgroup_files[] = { 464static struct cftype dev_cgroup_files[] = {
490 { 465 {
491 .name = "allow", 466 .name = "allow",
492 .write = devcgroup_access_write, 467 .write_string = devcgroup_access_write,
493 .private = DEVCG_ALLOW, 468 .private = DEVCG_ALLOW,
494 }, 469 },
495 { 470 {
496 .name = "deny", 471 .name = "deny",
497 .write = devcgroup_access_write, 472 .write_string = devcgroup_access_write,
498 .private = DEVCG_DENY, 473 .private = DEVCG_DENY,
499 }, 474 },
500 { 475 {