aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2012-11-06 15:26:23 -0500
committerTejun Heo <tj@kernel.org>2012-11-06 15:26:23 -0500
commit5b805f2a7675634fbdf9ac1c9b2256905ab2ea68 (patch)
treeee00d1e3d757458d66209b926d274491c6c3f61c /security
parent1db1e31b1ee3ae126ef98f39083b5f213c7b41bf (diff)
parent201e72acb2d3821e2de9ce6091e98859c316b29a (diff)
Merge branch 'cgroup/for-3.7-fixes' into cgroup/for-3.8
This is to receive device_cgroup fixes so that further device_cgroup changes can be made in cgroup/for-3.8. Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'security')
-rw-r--r--security/apparmor/Makefile2
-rw-r--r--security/apparmor/policy.c24
-rw-r--r--security/device_cgroup.c101
-rw-r--r--security/selinux/hooks.c18
4 files changed, 103 insertions, 42 deletions
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
index 7b3021cebbea..5706b74c857f 100644
--- a/security/apparmor/Makefile
+++ b/security/apparmor/Makefile
@@ -57,7 +57,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
57 57
58$(obj)/capability.o : $(obj)/capability_names.h 58$(obj)/capability.o : $(obj)/capability_names.h
59$(obj)/resource.o : $(obj)/rlim_names.h 59$(obj)/resource.o : $(obj)/rlim_names.h
60$(obj)/capability_names.h : $(srctree)/include/linux/capability.h \ 60$(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
61 $(src)/Makefile 61 $(src)/Makefile
62 $(call cmd,make-caps) 62 $(call cmd,make-caps)
63$(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \ 63$(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index cf5fd220309b..813200384d97 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -724,6 +724,8 @@ fail:
724 */ 724 */
725static void free_profile(struct aa_profile *profile) 725static void free_profile(struct aa_profile *profile)
726{ 726{
727 struct aa_profile *p;
728
727 AA_DEBUG("%s(%p)\n", __func__, profile); 729 AA_DEBUG("%s(%p)\n", __func__, profile);
728 730
729 if (!profile) 731 if (!profile)
@@ -751,7 +753,27 @@ static void free_profile(struct aa_profile *profile)
751 aa_put_dfa(profile->xmatch); 753 aa_put_dfa(profile->xmatch);
752 aa_put_dfa(profile->policy.dfa); 754 aa_put_dfa(profile->policy.dfa);
753 755
754 aa_put_profile(profile->replacedby); 756 /* put the profile reference for replacedby, but not via
757 * put_profile(kref_put).
758 * replacedby can form a long chain that can result in cascading
759 * frees that blows the stack because kref_put makes a nested fn
760 * call (it looks like recursion, with free_profile calling
761 * free_profile) for each profile in the chain lp#1056078.
762 */
763 for (p = profile->replacedby; p; ) {
764 if (atomic_dec_and_test(&p->base.count.refcount)) {
765 /* no more refs on p, grab its replacedby */
766 struct aa_profile *next = p->replacedby;
767 /* break the chain */
768 p->replacedby = NULL;
769 /* now free p, chain is broken */
770 free_profile(p);
771
772 /* follow up with next profile in the chain */
773 p = next;
774 } else
775 break;
776 }
755 777
756 kzfree(profile); 778 kzfree(profile);
757} 779}
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index 44dfc415a379..b08d20c66c2e 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -42,7 +42,10 @@ struct dev_exception_item {
42struct dev_cgroup { 42struct dev_cgroup {
43 struct cgroup_subsys_state css; 43 struct cgroup_subsys_state css;
44 struct list_head exceptions; 44 struct list_head exceptions;
45 bool deny_all; 45 enum {
46 DEVCG_DEFAULT_ALLOW,
47 DEVCG_DEFAULT_DENY,
48 } behavior;
46}; 49};
47 50
48static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s) 51static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s)
@@ -161,8 +164,8 @@ static void dev_exception_clean(struct dev_cgroup *dev_cgroup)
161 struct dev_exception_item *ex, *tmp; 164 struct dev_exception_item *ex, *tmp;
162 165
163 list_for_each_entry_safe(ex, tmp, &dev_cgroup->exceptions, list) { 166 list_for_each_entry_safe(ex, tmp, &dev_cgroup->exceptions, list) {
164 list_del(&ex->list); 167 list_del_rcu(&ex->list);
165 kfree(ex); 168 kfree_rcu(ex, rcu);
166 } 169 }
167} 170}
168 171
@@ -182,13 +185,13 @@ static struct cgroup_subsys_state *devcgroup_create(struct cgroup *cgroup)
182 parent_cgroup = cgroup->parent; 185 parent_cgroup = cgroup->parent;
183 186
184 if (parent_cgroup == NULL) 187 if (parent_cgroup == NULL)
185 dev_cgroup->deny_all = false; 188 dev_cgroup->behavior = DEVCG_DEFAULT_ALLOW;
186 else { 189 else {
187 parent_dev_cgroup = cgroup_to_devcgroup(parent_cgroup); 190 parent_dev_cgroup = cgroup_to_devcgroup(parent_cgroup);
188 mutex_lock(&devcgroup_mutex); 191 mutex_lock(&devcgroup_mutex);
189 ret = dev_exceptions_copy(&dev_cgroup->exceptions, 192 ret = dev_exceptions_copy(&dev_cgroup->exceptions,
190 &parent_dev_cgroup->exceptions); 193 &parent_dev_cgroup->exceptions);
191 dev_cgroup->deny_all = parent_dev_cgroup->deny_all; 194 dev_cgroup->behavior = parent_dev_cgroup->behavior;
192 mutex_unlock(&devcgroup_mutex); 195 mutex_unlock(&devcgroup_mutex);
193 if (ret) { 196 if (ret) {
194 kfree(dev_cgroup); 197 kfree(dev_cgroup);
@@ -260,7 +263,7 @@ static int devcgroup_seq_read(struct cgroup *cgroup, struct cftype *cft,
260 * - List the exceptions in case the default policy is to deny 263 * - List the exceptions in case the default policy is to deny
261 * This way, the file remains as a "whitelist of devices" 264 * This way, the file remains as a "whitelist of devices"
262 */ 265 */
263 if (devcgroup->deny_all == false) { 266 if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) {
264 set_access(acc, ACC_MASK); 267 set_access(acc, ACC_MASK);
265 set_majmin(maj, ~0); 268 set_majmin(maj, ~0);
266 set_majmin(min, ~0); 269 set_majmin(min, ~0);
@@ -295,7 +298,7 @@ static int may_access(struct dev_cgroup *dev_cgroup,
295 struct dev_exception_item *ex; 298 struct dev_exception_item *ex;
296 bool match = false; 299 bool match = false;
297 300
298 list_for_each_entry(ex, &dev_cgroup->exceptions, list) { 301 list_for_each_entry_rcu(ex, &dev_cgroup->exceptions, list) {
299 if ((refex->type & DEV_BLOCK) && !(ex->type & DEV_BLOCK)) 302 if ((refex->type & DEV_BLOCK) && !(ex->type & DEV_BLOCK))
300 continue; 303 continue;
301 if ((refex->type & DEV_CHAR) && !(ex->type & DEV_CHAR)) 304 if ((refex->type & DEV_CHAR) && !(ex->type & DEV_CHAR))
@@ -314,12 +317,12 @@ static int may_access(struct dev_cgroup *dev_cgroup,
314 * In two cases we'll consider this new exception valid: 317 * In two cases we'll consider this new exception valid:
315 * - the dev cgroup has its default policy to allow + exception list: 318 * - the dev cgroup has its default policy to allow + exception list:
316 * the new exception should *not* match any of the exceptions 319 * the new exception should *not* match any of the exceptions
317 * (!deny_all, !match) 320 * (behavior == DEVCG_DEFAULT_ALLOW, !match)
318 * - the dev cgroup has its default policy to deny + exception list: 321 * - the dev cgroup has its default policy to deny + exception list:
319 * the new exception *should* match the exceptions 322 * the new exception *should* match the exceptions
320 * (deny_all, match) 323 * (behavior == DEVCG_DEFAULT_DENY, match)
321 */ 324 */
322 if (dev_cgroup->deny_all == match) 325 if ((dev_cgroup->behavior == DEVCG_DEFAULT_DENY) == match)
323 return 1; 326 return 1;
324 return 0; 327 return 0;
325} 328}
@@ -341,6 +344,19 @@ static int parent_has_perm(struct dev_cgroup *childcg,
341 return may_access(parent, ex); 344 return may_access(parent, ex);
342} 345}
343 346
347/**
348 * may_allow_all - checks if it's possible to change the behavior to
349 * allow based on parent's rules.
350 * @parent: device cgroup's parent
351 * returns: != 0 in case it's allowed, 0 otherwise
352 */
353static inline int may_allow_all(struct dev_cgroup *parent)
354{
355 if (!parent)
356 return 1;
357 return parent->behavior == DEVCG_DEFAULT_ALLOW;
358}
359
344/* 360/*
345 * Modify the exception list using allow/deny rules. 361 * Modify the exception list using allow/deny rules.
346 * CAP_SYS_ADMIN is needed for this. It's at least separate from CAP_MKNOD 362 * CAP_SYS_ADMIN is needed for this. It's at least separate from CAP_MKNOD
@@ -358,13 +374,18 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
358 int filetype, const char *buffer) 374 int filetype, const char *buffer)
359{ 375{
360 const char *b; 376 const char *b;
361 char *endp; 377 char temp[12]; /* 11 + 1 characters needed for a u32 */
362 int count; 378 int count, rc;
363 struct dev_exception_item ex; 379 struct dev_exception_item ex;
380 struct cgroup *p = devcgroup->css.cgroup;
381 struct dev_cgroup *parent = NULL;
364 382
365 if (!capable(CAP_SYS_ADMIN)) 383 if (!capable(CAP_SYS_ADMIN))
366 return -EPERM; 384 return -EPERM;
367 385
386 if (p->parent)
387 parent = cgroup_to_devcgroup(p->parent);
388
368 memset(&ex, 0, sizeof(ex)); 389 memset(&ex, 0, sizeof(ex));
369 b = buffer; 390 b = buffer;
370 391
@@ -372,14 +393,21 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
372 case 'a': 393 case 'a':
373 switch (filetype) { 394 switch (filetype) {
374 case DEVCG_ALLOW: 395 case DEVCG_ALLOW:
375 if (!parent_has_perm(devcgroup, &ex)) 396 if (!may_allow_all(parent))
376 return -EPERM; 397 return -EPERM;
377 dev_exception_clean(devcgroup); 398 dev_exception_clean(devcgroup);
378 devcgroup->deny_all = false; 399 devcgroup->behavior = DEVCG_DEFAULT_ALLOW;
400 if (!parent)
401 break;
402
403 rc = dev_exceptions_copy(&devcgroup->exceptions,
404 &parent->exceptions);
405 if (rc)
406 return rc;
379 break; 407 break;
380 case DEVCG_DENY: 408 case DEVCG_DENY:
381 dev_exception_clean(devcgroup); 409 dev_exception_clean(devcgroup);
382 devcgroup->deny_all = true; 410 devcgroup->behavior = DEVCG_DEFAULT_DENY;
383 break; 411 break;
384 default: 412 default:
385 return -EINVAL; 413 return -EINVAL;
@@ -402,8 +430,16 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
402 ex.major = ~0; 430 ex.major = ~0;
403 b++; 431 b++;
404 } else if (isdigit(*b)) { 432 } else if (isdigit(*b)) {
405 ex.major = simple_strtoul(b, &endp, 10); 433 memset(temp, 0, sizeof(temp));
406 b = endp; 434 for (count = 0; count < sizeof(temp) - 1; count++) {
435 temp[count] = *b;
436 b++;
437 if (!isdigit(*b))
438 break;
439 }
440 rc = kstrtou32(temp, 10, &ex.major);
441 if (rc)
442 return -EINVAL;
407 } else { 443 } else {
408 return -EINVAL; 444 return -EINVAL;
409 } 445 }
@@ -416,8 +452,16 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
416 ex.minor = ~0; 452 ex.minor = ~0;
417 b++; 453 b++;
418 } else if (isdigit(*b)) { 454 } else if (isdigit(*b)) {
419 ex.minor = simple_strtoul(b, &endp, 10); 455 memset(temp, 0, sizeof(temp));
420 b = endp; 456 for (count = 0; count < sizeof(temp) - 1; count++) {
457 temp[count] = *b;
458 b++;
459 if (!isdigit(*b))
460 break;
461 }
462 rc = kstrtou32(temp, 10, &ex.minor);
463 if (rc)
464 return -EINVAL;
421 } else { 465 } else {
422 return -EINVAL; 466 return -EINVAL;
423 } 467 }
@@ -452,7 +496,7 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
452 * an matching exception instead. And be silent about it: we 496 * an matching exception instead. And be silent about it: we
453 * don't want to break compatibility 497 * don't want to break compatibility
454 */ 498 */
455 if (devcgroup->deny_all == false) { 499 if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) {
456 dev_exception_rm(devcgroup, &ex); 500 dev_exception_rm(devcgroup, &ex);
457 return 0; 501 return 0;
458 } 502 }
@@ -463,7 +507,7 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
463 * an matching exception instead. And be silent about it: we 507 * an matching exception instead. And be silent about it: we
464 * don't want to break compatibility 508 * don't want to break compatibility
465 */ 509 */
466 if (devcgroup->deny_all == true) { 510 if (devcgroup->behavior == DEVCG_DEFAULT_DENY) {
467 dev_exception_rm(devcgroup, &ex); 511 dev_exception_rm(devcgroup, &ex);
468 return 0; 512 return 0;
469 } 513 }
@@ -533,10 +577,10 @@ struct cgroup_subsys devices_subsys = {
533 * 577 *
534 * returns 0 on success, -EPERM case the operation is not permitted 578 * returns 0 on success, -EPERM case the operation is not permitted
535 */ 579 */
536static int __devcgroup_check_permission(struct dev_cgroup *dev_cgroup, 580static int __devcgroup_check_permission(short type, u32 major, u32 minor,
537 short type, u32 major, u32 minor,
538 short access) 581 short access)
539{ 582{
583 struct dev_cgroup *dev_cgroup;
540 struct dev_exception_item ex; 584 struct dev_exception_item ex;
541 int rc; 585 int rc;
542 586
@@ -547,6 +591,7 @@ static int __devcgroup_check_permission(struct dev_cgroup *dev_cgroup,
547 ex.access = access; 591 ex.access = access;
548 592
549 rcu_read_lock(); 593 rcu_read_lock();
594 dev_cgroup = task_devcgroup(current);
550 rc = may_access(dev_cgroup, &ex); 595 rc = may_access(dev_cgroup, &ex);
551 rcu_read_unlock(); 596 rcu_read_unlock();
552 597
@@ -558,7 +603,6 @@ static int __devcgroup_check_permission(struct dev_cgroup *dev_cgroup,
558 603
559int __devcgroup_inode_permission(struct inode *inode, int mask) 604int __devcgroup_inode_permission(struct inode *inode, int mask)
560{ 605{
561 struct dev_cgroup *dev_cgroup = task_devcgroup(current);
562 short type, access = 0; 606 short type, access = 0;
563 607
564 if (S_ISBLK(inode->i_mode)) 608 if (S_ISBLK(inode->i_mode))
@@ -570,13 +614,12 @@ int __devcgroup_inode_permission(struct inode *inode, int mask)
570 if (mask & MAY_READ) 614 if (mask & MAY_READ)
571 access |= ACC_READ; 615 access |= ACC_READ;
572 616
573 return __devcgroup_check_permission(dev_cgroup, type, imajor(inode), 617 return __devcgroup_check_permission(type, imajor(inode), iminor(inode),
574 iminor(inode), access); 618 access);
575} 619}
576 620
577int devcgroup_inode_mknod(int mode, dev_t dev) 621int devcgroup_inode_mknod(int mode, dev_t dev)
578{ 622{
579 struct dev_cgroup *dev_cgroup = task_devcgroup(current);
580 short type; 623 short type;
581 624
582 if (!S_ISBLK(mode) && !S_ISCHR(mode)) 625 if (!S_ISBLK(mode) && !S_ISCHR(mode))
@@ -587,7 +630,7 @@ int devcgroup_inode_mknod(int mode, dev_t dev)
587 else 630 else
588 type = DEV_CHAR; 631 type = DEV_CHAR;
589 632
590 return __devcgroup_check_permission(dev_cgroup, type, MAJOR(dev), 633 return __devcgroup_check_permission(type, MAJOR(dev), MINOR(dev),
591 MINOR(dev), ACC_MKNOD); 634 ACC_MKNOD);
592 635
593} 636}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 24ab4148547c..61a53367d029 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2132,18 +2132,14 @@ static inline void flush_unauthorized_files(const struct cred *cred,
2132 return; 2132 return;
2133 2133
2134 devnull = dentry_open(&selinux_null, O_RDWR, cred); 2134 devnull = dentry_open(&selinux_null, O_RDWR, cred);
2135 if (!IS_ERR(devnull)) { 2135 if (IS_ERR(devnull))
2136 /* replace all the matching ones with this */ 2136 devnull = NULL;
2137 do { 2137 /* replace all the matching ones with this */
2138 replace_fd(n - 1, get_file(devnull), 0); 2138 do {
2139 } while ((n = iterate_fd(files, n, match_file, cred)) != 0); 2139 replace_fd(n - 1, devnull, 0);
2140 } while ((n = iterate_fd(files, n, match_file, cred)) != 0);
2141 if (devnull)
2140 fput(devnull); 2142 fput(devnull);
2141 } else {
2142 /* just close all the matching ones */
2143 do {
2144 replace_fd(n - 1, NULL, 0);
2145 } while ((n = iterate_fd(files, n, match_file, cred)) != 0);
2146 }
2147} 2143}
2148 2144
2149/* 2145/*