Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Paul Menage and committed by
Linus Torvalds
f92523e3 e3712395

+38 -63
+38 -63
security/device_cgroup.c
··· 59 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 67 struct cgroup_subsys devices_subsys; 63 68 64 69 static int devcgroup_can_attach(struct cgroup_subsys *ss, ··· 317 312 * when adding a new allow rule to a device whitelist, the rule 318 313 * must be allowed in the parent device 319 314 */ 320 - static int parent_has_perm(struct cgroup *childcg, 315 + static int parent_has_perm(struct dev_cgroup *childcg, 321 316 struct dev_whitelist_item *wh) 322 317 { 323 - struct cgroup *pcg = childcg->parent; 318 + struct cgroup *pcg = childcg->css.cgroup->parent; 324 319 struct dev_cgroup *parent; 325 320 int ret; 326 321 ··· 346 341 * new access is only allowed if you're in the top-level cgroup, or your 347 342 * parent cgroup has the access you're asking for. 348 343 */ 349 - static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft, 350 - struct file *file, const char __user *userbuf, 351 - size_t nbytes, loff_t *ppos) 344 + static int devcgroup_update_access(struct dev_cgroup *devcgroup, 345 + int filetype, const char *buffer) 352 346 { 353 - struct cgroup *cur_cgroup; 354 - struct dev_cgroup *devcgroup, *cur_devcgroup; 355 - int filetype = cft->private; 356 - char *buffer, *b; 347 + struct dev_cgroup *cur_devcgroup; 348 + const char *b; 357 349 int retval = 0, count; 358 350 struct dev_whitelist_item wh; 359 351 360 352 if (!capable(CAP_SYS_ADMIN)) 361 353 return -EPERM; 362 354 363 - devcgroup = cgroup_to_devcgroup(cgroup); 364 - cur_cgroup = task_cgroup(current, devices_subsys.subsys_id); 365 - cur_devcgroup = cgroup_to_devcgroup(cur_cgroup); 366 - 367 - buffer = kmalloc(nbytes+1, GFP_KERNEL); 368 - if (!buffer) 369 - return -ENOMEM; 370 - 371 - if (copy_from_user(buffer, userbuf, nbytes)) { 372 - retval = -EFAULT; 373 - goto out1; 374 - } 375 - buffer[nbytes] = 0; /* nul-terminate */ 376 - 377 - cgroup_lock(); 378 - if (cgroup_is_removed(cgroup)) { 379 - retval = -ENODEV; 380 - goto out2; 381 - } 355 + cur_devcgroup = task_devcgroup(current); 382 356 383 357 memset(&wh, 0, sizeof(wh)); 384 358 b = buffer; ··· 376 392 wh.type = DEV_CHAR; 377 393 break; 378 394 default: 379 - retval = -EINVAL; 380 - goto out2; 395 + return -EINVAL; 381 396 } 382 397 b++; 383 - if (!isspace(*b)) { 384 - retval = -EINVAL; 385 - goto out2; 386 - } 398 + if (!isspace(*b)) 399 + return -EINVAL; 387 400 b++; 388 401 if (*b == '*') { 389 402 wh.major = ~0; ··· 392 411 b++; 393 412 } 394 413 } else { 395 - retval = -EINVAL; 396 - goto out2; 414 + return -EINVAL; 397 415 } 398 - if (*b != ':') { 399 - retval = -EINVAL; 400 - goto out2; 401 - } 416 + if (*b != ':') 417 + return -EINVAL; 402 418 b++; 403 419 404 420 /* read minor */ ··· 409 431 b++; 410 432 } 411 433 } else { 412 - retval = -EINVAL; 413 - goto out2; 434 + return -EINVAL; 414 435 } 415 - if (!isspace(*b)) { 416 - retval = -EINVAL; 417 - goto out2; 418 - } 436 + if (!isspace(*b)) 437 + return -EINVAL; 419 438 for (b++, count = 0; count < 3; count++, b++) { 420 439 switch (*b) { 421 440 case 'r': ··· 429 454 count = 3; 430 455 break; 431 456 default: 432 - retval = -EINVAL; 433 - goto out2; 457 + return -EINVAL; 434 458 } 435 459 } 436 460 ··· 437 463 retval = 0; 438 464 switch (filetype) { 439 465 case DEVCG_ALLOW: 440 - if (!parent_has_perm(cgroup, &wh)) 441 - retval = -EPERM; 442 - else 443 - retval = dev_whitelist_add(devcgroup, &wh); 444 - break; 466 + if (!parent_has_perm(devcgroup, &wh)) 467 + return -EPERM; 468 + return dev_whitelist_add(devcgroup, &wh); 445 469 case DEVCG_DENY: 446 470 dev_whitelist_rm(devcgroup, &wh); 447 471 break; 448 472 default: 449 - retval = -EINVAL; 450 - goto out2; 473 + return -EINVAL; 451 474 } 475 + return 0; 476 + } 452 477 453 - if (retval == 0) 454 - retval = nbytes; 455 - 456 - out2: 478 + static int devcgroup_access_write(struct cgroup *cgrp, struct cftype *cft, 479 + const char *buffer) 480 + { 481 + int retval; 482 + if (!cgroup_lock_live_group(cgrp)) 483 + return -ENODEV; 484 + retval = devcgroup_update_access(cgroup_to_devcgroup(cgrp), 485 + cft->private, buffer); 457 486 cgroup_unlock(); 458 - out1: 459 - kfree(buffer); 460 487 return retval; 461 488 } 462 489 463 490 static struct cftype dev_cgroup_files[] = { 464 491 { 465 492 .name = "allow", 466 - .write = devcgroup_access_write, 493 + .write_string = devcgroup_access_write, 467 494 .private = DEVCG_ALLOW, 468 495 }, 469 496 { 470 497 .name = "deny", 471 - .write = devcgroup_access_write, 498 + .write_string = devcgroup_access_write, 472 499 .private = DEVCG_DENY, 473 500 }, 474 501 {