diff options
| author | Paul Menage <menage@google.com> | 2008-07-25 04:47:03 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-25 13:53:36 -0400 |
| commit | f92523e3a7861f5dbd76021e0719a35fe8771f2d (patch) | |
| tree | 933c9e6e1f0683ac1c6bc019da5b91c9e567bf7c /security | |
| parent | e37123953292146445c8629b3950d0513fd10ae2 (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.c | 101 |
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 | ||
| 62 | static 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 | |||
| 62 | struct cgroup_subsys devices_subsys; | 67 | struct cgroup_subsys devices_subsys; |
| 63 | 68 | ||
| 64 | static int devcgroup_can_attach(struct cgroup_subsys *ss, | 69 | static 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 | */ |
| 315 | static int parent_has_perm(struct cgroup *childcg, | 320 | static 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 | */ |
| 344 | static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft, | 349 | static 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) | 452 | static int devcgroup_access_write(struct cgroup *cgrp, struct cftype *cft, |
| 480 | retval = nbytes; | 453 | const char *buffer) |
| 481 | 454 | { | |
| 482 | out2: | 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(); |
| 484 | out1: | ||
| 485 | kfree(buffer); | ||
| 486 | return retval; | 461 | return retval; |
| 487 | } | 462 | } |
| 488 | 463 | ||
| 489 | static struct cftype dev_cgroup_files[] = { | 464 | static 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 | { |
