diff options
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r-- | security/selinux/hooks.c | 581 |
1 files changed, 420 insertions, 161 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 21dad415b896..a91c961ba38b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * as published by the Free Software Foundation. | 18 | * as published by the Free Software Foundation. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/config.h> | ||
22 | #include <linux/module.h> | 21 | #include <linux/module.h> |
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
@@ -69,6 +68,7 @@ | |||
69 | #include <linux/sysctl.h> | 68 | #include <linux/sysctl.h> |
70 | #include <linux/audit.h> | 69 | #include <linux/audit.h> |
71 | #include <linux/string.h> | 70 | #include <linux/string.h> |
71 | #include <linux/selinux.h> | ||
72 | 72 | ||
73 | #include "avc.h" | 73 | #include "avc.h" |
74 | #include "objsec.h" | 74 | #include "objsec.h" |
@@ -80,6 +80,7 @@ | |||
80 | 80 | ||
81 | extern unsigned int policydb_loaded_version; | 81 | extern unsigned int policydb_loaded_version; |
82 | extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); | 82 | extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); |
83 | extern int selinux_compat_net; | ||
83 | 84 | ||
84 | #ifdef CONFIG_SECURITY_SELINUX_DEVELOP | 85 | #ifdef CONFIG_SECURITY_SELINUX_DEVELOP |
85 | int selinux_enforcing = 0; | 86 | int selinux_enforcing = 0; |
@@ -245,6 +246,7 @@ static int superblock_alloc_security(struct super_block *sb) | |||
245 | sbsec->sb = sb; | 246 | sbsec->sb = sb; |
246 | sbsec->sid = SECINITSID_UNLABELED; | 247 | sbsec->sid = SECINITSID_UNLABELED; |
247 | sbsec->def_sid = SECINITSID_FILE; | 248 | sbsec->def_sid = SECINITSID_FILE; |
249 | sbsec->mntpoint_sid = SECINITSID_UNLABELED; | ||
248 | sb->s_security = sbsec; | 250 | sb->s_security = sbsec; |
249 | 251 | ||
250 | return 0; | 252 | return 0; |
@@ -318,19 +320,53 @@ enum { | |||
318 | Opt_context = 1, | 320 | Opt_context = 1, |
319 | Opt_fscontext = 2, | 321 | Opt_fscontext = 2, |
320 | Opt_defcontext = 4, | 322 | Opt_defcontext = 4, |
323 | Opt_rootcontext = 8, | ||
321 | }; | 324 | }; |
322 | 325 | ||
323 | static match_table_t tokens = { | 326 | static match_table_t tokens = { |
324 | {Opt_context, "context=%s"}, | 327 | {Opt_context, "context=%s"}, |
325 | {Opt_fscontext, "fscontext=%s"}, | 328 | {Opt_fscontext, "fscontext=%s"}, |
326 | {Opt_defcontext, "defcontext=%s"}, | 329 | {Opt_defcontext, "defcontext=%s"}, |
330 | {Opt_rootcontext, "rootcontext=%s"}, | ||
327 | }; | 331 | }; |
328 | 332 | ||
329 | #define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n" | 333 | #define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n" |
330 | 334 | ||
335 | static int may_context_mount_sb_relabel(u32 sid, | ||
336 | struct superblock_security_struct *sbsec, | ||
337 | struct task_security_struct *tsec) | ||
338 | { | ||
339 | int rc; | ||
340 | |||
341 | rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, | ||
342 | FILESYSTEM__RELABELFROM, NULL); | ||
343 | if (rc) | ||
344 | return rc; | ||
345 | |||
346 | rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM, | ||
347 | FILESYSTEM__RELABELTO, NULL); | ||
348 | return rc; | ||
349 | } | ||
350 | |||
351 | static int may_context_mount_inode_relabel(u32 sid, | ||
352 | struct superblock_security_struct *sbsec, | ||
353 | struct task_security_struct *tsec) | ||
354 | { | ||
355 | int rc; | ||
356 | rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, | ||
357 | FILESYSTEM__RELABELFROM, NULL); | ||
358 | if (rc) | ||
359 | return rc; | ||
360 | |||
361 | rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, | ||
362 | FILESYSTEM__ASSOCIATE, NULL); | ||
363 | return rc; | ||
364 | } | ||
365 | |||
331 | static int try_context_mount(struct super_block *sb, void *data) | 366 | static int try_context_mount(struct super_block *sb, void *data) |
332 | { | 367 | { |
333 | char *context = NULL, *defcontext = NULL; | 368 | char *context = NULL, *defcontext = NULL; |
369 | char *fscontext = NULL, *rootcontext = NULL; | ||
334 | const char *name; | 370 | const char *name; |
335 | u32 sid; | 371 | u32 sid; |
336 | int alloc = 0, rc = 0, seen = 0; | 372 | int alloc = 0, rc = 0, seen = 0; |
@@ -373,7 +409,7 @@ static int try_context_mount(struct super_block *sb, void *data) | |||
373 | 409 | ||
374 | switch (token) { | 410 | switch (token) { |
375 | case Opt_context: | 411 | case Opt_context: |
376 | if (seen) { | 412 | if (seen & (Opt_context|Opt_defcontext)) { |
377 | rc = -EINVAL; | 413 | rc = -EINVAL; |
378 | printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); | 414 | printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); |
379 | goto out_free; | 415 | goto out_free; |
@@ -389,13 +425,13 @@ static int try_context_mount(struct super_block *sb, void *data) | |||
389 | break; | 425 | break; |
390 | 426 | ||
391 | case Opt_fscontext: | 427 | case Opt_fscontext: |
392 | if (seen & (Opt_context|Opt_fscontext)) { | 428 | if (seen & Opt_fscontext) { |
393 | rc = -EINVAL; | 429 | rc = -EINVAL; |
394 | printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); | 430 | printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); |
395 | goto out_free; | 431 | goto out_free; |
396 | } | 432 | } |
397 | context = match_strdup(&args[0]); | 433 | fscontext = match_strdup(&args[0]); |
398 | if (!context) { | 434 | if (!fscontext) { |
399 | rc = -ENOMEM; | 435 | rc = -ENOMEM; |
400 | goto out_free; | 436 | goto out_free; |
401 | } | 437 | } |
@@ -404,6 +440,22 @@ static int try_context_mount(struct super_block *sb, void *data) | |||
404 | seen |= Opt_fscontext; | 440 | seen |= Opt_fscontext; |
405 | break; | 441 | break; |
406 | 442 | ||
443 | case Opt_rootcontext: | ||
444 | if (seen & Opt_rootcontext) { | ||
445 | rc = -EINVAL; | ||
446 | printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); | ||
447 | goto out_free; | ||
448 | } | ||
449 | rootcontext = match_strdup(&args[0]); | ||
450 | if (!rootcontext) { | ||
451 | rc = -ENOMEM; | ||
452 | goto out_free; | ||
453 | } | ||
454 | if (!alloc) | ||
455 | alloc = 1; | ||
456 | seen |= Opt_rootcontext; | ||
457 | break; | ||
458 | |||
407 | case Opt_defcontext: | 459 | case Opt_defcontext: |
408 | if (sbsec->behavior != SECURITY_FS_USE_XATTR) { | 460 | if (sbsec->behavior != SECURITY_FS_USE_XATTR) { |
409 | rc = -EINVAL; | 461 | rc = -EINVAL; |
@@ -440,6 +492,28 @@ static int try_context_mount(struct super_block *sb, void *data) | |||
440 | if (!seen) | 492 | if (!seen) |
441 | goto out; | 493 | goto out; |
442 | 494 | ||
495 | /* sets the context of the superblock for the fs being mounted. */ | ||
496 | if (fscontext) { | ||
497 | rc = security_context_to_sid(fscontext, strlen(fscontext), &sid); | ||
498 | if (rc) { | ||
499 | printk(KERN_WARNING "SELinux: security_context_to_sid" | ||
500 | "(%s) failed for (dev %s, type %s) errno=%d\n", | ||
501 | fscontext, sb->s_id, name, rc); | ||
502 | goto out_free; | ||
503 | } | ||
504 | |||
505 | rc = may_context_mount_sb_relabel(sid, sbsec, tsec); | ||
506 | if (rc) | ||
507 | goto out_free; | ||
508 | |||
509 | sbsec->sid = sid; | ||
510 | } | ||
511 | |||
512 | /* | ||
513 | * Switch to using mount point labeling behavior. | ||
514 | * sets the label used on all file below the mountpoint, and will set | ||
515 | * the superblock context if not already set. | ||
516 | */ | ||
443 | if (context) { | 517 | if (context) { |
444 | rc = security_context_to_sid(context, strlen(context), &sid); | 518 | rc = security_context_to_sid(context, strlen(context), &sid); |
445 | if (rc) { | 519 | if (rc) { |
@@ -449,20 +523,38 @@ static int try_context_mount(struct super_block *sb, void *data) | |||
449 | goto out_free; | 523 | goto out_free; |
450 | } | 524 | } |
451 | 525 | ||
452 | rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, | 526 | if (!fscontext) { |
453 | FILESYSTEM__RELABELFROM, NULL); | 527 | rc = may_context_mount_sb_relabel(sid, sbsec, tsec); |
454 | if (rc) | 528 | if (rc) |
529 | goto out_free; | ||
530 | sbsec->sid = sid; | ||
531 | } else { | ||
532 | rc = may_context_mount_inode_relabel(sid, sbsec, tsec); | ||
533 | if (rc) | ||
534 | goto out_free; | ||
535 | } | ||
536 | sbsec->mntpoint_sid = sid; | ||
537 | |||
538 | sbsec->behavior = SECURITY_FS_USE_MNTPOINT; | ||
539 | } | ||
540 | |||
541 | if (rootcontext) { | ||
542 | struct inode *inode = sb->s_root->d_inode; | ||
543 | struct inode_security_struct *isec = inode->i_security; | ||
544 | rc = security_context_to_sid(rootcontext, strlen(rootcontext), &sid); | ||
545 | if (rc) { | ||
546 | printk(KERN_WARNING "SELinux: security_context_to_sid" | ||
547 | "(%s) failed for (dev %s, type %s) errno=%d\n", | ||
548 | rootcontext, sb->s_id, name, rc); | ||
455 | goto out_free; | 549 | goto out_free; |
550 | } | ||
456 | 551 | ||
457 | rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM, | 552 | rc = may_context_mount_inode_relabel(sid, sbsec, tsec); |
458 | FILESYSTEM__RELABELTO, NULL); | ||
459 | if (rc) | 553 | if (rc) |
460 | goto out_free; | 554 | goto out_free; |
461 | 555 | ||
462 | sbsec->sid = sid; | 556 | isec->sid = sid; |
463 | 557 | isec->initialized = 1; | |
464 | if (seen & Opt_context) | ||
465 | sbsec->behavior = SECURITY_FS_USE_MNTPOINT; | ||
466 | } | 558 | } |
467 | 559 | ||
468 | if (defcontext) { | 560 | if (defcontext) { |
@@ -477,13 +569,7 @@ static int try_context_mount(struct super_block *sb, void *data) | |||
477 | if (sid == sbsec->def_sid) | 569 | if (sid == sbsec->def_sid) |
478 | goto out_free; | 570 | goto out_free; |
479 | 571 | ||
480 | rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, | 572 | rc = may_context_mount_inode_relabel(sid, sbsec, tsec); |
481 | FILESYSTEM__RELABELFROM, NULL); | ||
482 | if (rc) | ||
483 | goto out_free; | ||
484 | |||
485 | rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, | ||
486 | FILESYSTEM__ASSOCIATE, NULL); | ||
487 | if (rc) | 573 | if (rc) |
488 | goto out_free; | 574 | goto out_free; |
489 | 575 | ||
@@ -494,6 +580,8 @@ out_free: | |||
494 | if (alloc) { | 580 | if (alloc) { |
495 | kfree(context); | 581 | kfree(context); |
496 | kfree(defcontext); | 582 | kfree(defcontext); |
583 | kfree(fscontext); | ||
584 | kfree(rootcontext); | ||
497 | } | 585 | } |
498 | out: | 586 | out: |
499 | return rc; | 587 | return rc; |
@@ -696,6 +784,8 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc | |||
696 | return SECCLASS_PACKET_SOCKET; | 784 | return SECCLASS_PACKET_SOCKET; |
697 | case PF_KEY: | 785 | case PF_KEY: |
698 | return SECCLASS_KEY_SOCKET; | 786 | return SECCLASS_KEY_SOCKET; |
787 | case PF_APPLETALK: | ||
788 | return SECCLASS_APPLETALK_SOCKET; | ||
699 | } | 789 | } |
700 | 790 | ||
701 | return SECCLASS_SOCKET; | 791 | return SECCLASS_SOCKET; |
@@ -873,8 +963,11 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
873 | goto out; | 963 | goto out; |
874 | isec->sid = sid; | 964 | isec->sid = sid; |
875 | break; | 965 | break; |
966 | case SECURITY_FS_USE_MNTPOINT: | ||
967 | isec->sid = sbsec->mntpoint_sid; | ||
968 | break; | ||
876 | default: | 969 | default: |
877 | /* Default to the fs SID. */ | 970 | /* Default to the fs superblock SID. */ |
878 | isec->sid = sbsec->sid; | 971 | isec->sid = sbsec->sid; |
879 | 972 | ||
880 | if (sbsec->proc) { | 973 | if (sbsec->proc) { |
@@ -1096,6 +1189,17 @@ static int may_create(struct inode *dir, | |||
1096 | FILESYSTEM__ASSOCIATE, &ad); | 1189 | FILESYSTEM__ASSOCIATE, &ad); |
1097 | } | 1190 | } |
1098 | 1191 | ||
1192 | /* Check whether a task can create a key. */ | ||
1193 | static int may_create_key(u32 ksid, | ||
1194 | struct task_struct *ctx) | ||
1195 | { | ||
1196 | struct task_security_struct *tsec; | ||
1197 | |||
1198 | tsec = ctx->security; | ||
1199 | |||
1200 | return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL); | ||
1201 | } | ||
1202 | |||
1099 | #define MAY_LINK 0 | 1203 | #define MAY_LINK 0 |
1100 | #define MAY_UNLINK 1 | 1204 | #define MAY_UNLINK 1 |
1101 | #define MAY_RMDIR 2 | 1205 | #define MAY_RMDIR 2 |
@@ -1518,8 +1622,10 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm) | |||
1518 | /* Default to the current task SID. */ | 1622 | /* Default to the current task SID. */ |
1519 | bsec->sid = tsec->sid; | 1623 | bsec->sid = tsec->sid; |
1520 | 1624 | ||
1521 | /* Reset create SID on execve. */ | 1625 | /* Reset fs, key, and sock SIDs on execve. */ |
1522 | tsec->create_sid = 0; | 1626 | tsec->create_sid = 0; |
1627 | tsec->keycreate_sid = 0; | ||
1628 | tsec->sockcreate_sid = 0; | ||
1523 | 1629 | ||
1524 | if (tsec->exec_sid) { | 1630 | if (tsec->exec_sid) { |
1525 | newsid = tsec->exec_sid; | 1631 | newsid = tsec->exec_sid; |
@@ -1827,7 +1933,8 @@ static inline int selinux_option(char *option, int len) | |||
1827 | { | 1933 | { |
1828 | return (match_prefix("context=", sizeof("context=")-1, option, len) || | 1934 | return (match_prefix("context=", sizeof("context=")-1, option, len) || |
1829 | match_prefix("fscontext=", sizeof("fscontext=")-1, option, len) || | 1935 | match_prefix("fscontext=", sizeof("fscontext=")-1, option, len) || |
1830 | match_prefix("defcontext=", sizeof("defcontext=")-1, option, len)); | 1936 | match_prefix("defcontext=", sizeof("defcontext=")-1, option, len) || |
1937 | match_prefix("rootcontext=", sizeof("rootcontext=")-1, option, len)); | ||
1831 | } | 1938 | } |
1832 | 1939 | ||
1833 | static inline void take_option(char **to, char *from, int *first, int len) | 1940 | static inline void take_option(char **to, char *from, int *first, int len) |
@@ -1900,13 +2007,13 @@ static int selinux_sb_kern_mount(struct super_block *sb, void *data) | |||
1900 | return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad); | 2007 | return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad); |
1901 | } | 2008 | } |
1902 | 2009 | ||
1903 | static int selinux_sb_statfs(struct super_block *sb) | 2010 | static int selinux_sb_statfs(struct dentry *dentry) |
1904 | { | 2011 | { |
1905 | struct avc_audit_data ad; | 2012 | struct avc_audit_data ad; |
1906 | 2013 | ||
1907 | AVC_AUDIT_DATA_INIT(&ad,FS); | 2014 | AVC_AUDIT_DATA_INIT(&ad,FS); |
1908 | ad.u.fs.dentry = sb->s_root; | 2015 | ad.u.fs.dentry = dentry->d_sb->s_root; |
1909 | return superblock_has_perm(current, sb, FILESYSTEM__GETATTR, &ad); | 2016 | return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad); |
1910 | } | 2017 | } |
1911 | 2018 | ||
1912 | static int selinux_mount(char * dev_name, | 2019 | static int selinux_mount(char * dev_name, |
@@ -2571,9 +2678,11 @@ static int selinux_task_alloc_security(struct task_struct *tsk) | |||
2571 | tsec2->osid = tsec1->osid; | 2678 | tsec2->osid = tsec1->osid; |
2572 | tsec2->sid = tsec1->sid; | 2679 | tsec2->sid = tsec1->sid; |
2573 | 2680 | ||
2574 | /* Retain the exec and create SIDs across fork */ | 2681 | /* Retain the exec, fs, key, and sock SIDs across fork */ |
2575 | tsec2->exec_sid = tsec1->exec_sid; | 2682 | tsec2->exec_sid = tsec1->exec_sid; |
2576 | tsec2->create_sid = tsec1->create_sid; | 2683 | tsec2->create_sid = tsec1->create_sid; |
2684 | tsec2->keycreate_sid = tsec1->keycreate_sid; | ||
2685 | tsec2->sockcreate_sid = tsec1->sockcreate_sid; | ||
2577 | 2686 | ||
2578 | /* Retain ptracer SID across fork, if any. | 2687 | /* Retain ptracer SID across fork, if any. |
2579 | This will be reset by the ptrace hook upon any | 2688 | This will be reset by the ptrace hook upon any |
@@ -2625,6 +2734,11 @@ static int selinux_task_getsid(struct task_struct *p) | |||
2625 | return task_has_perm(current, p, PROCESS__GETSESSION); | 2734 | return task_has_perm(current, p, PROCESS__GETSESSION); |
2626 | } | 2735 | } |
2627 | 2736 | ||
2737 | static void selinux_task_getsecid(struct task_struct *p, u32 *secid) | ||
2738 | { | ||
2739 | selinux_get_task_sid(p, secid); | ||
2740 | } | ||
2741 | |||
2628 | static int selinux_task_setgroups(struct group_info *group_info) | 2742 | static int selinux_task_setgroups(struct group_info *group_info) |
2629 | { | 2743 | { |
2630 | /* See the comment for setuid above. */ | 2744 | /* See the comment for setuid above. */ |
@@ -2642,6 +2756,16 @@ static int selinux_task_setnice(struct task_struct *p, int nice) | |||
2642 | return task_has_perm(current,p, PROCESS__SETSCHED); | 2756 | return task_has_perm(current,p, PROCESS__SETSCHED); |
2643 | } | 2757 | } |
2644 | 2758 | ||
2759 | static int selinux_task_setioprio(struct task_struct *p, int ioprio) | ||
2760 | { | ||
2761 | return task_has_perm(current, p, PROCESS__SETSCHED); | ||
2762 | } | ||
2763 | |||
2764 | static int selinux_task_getioprio(struct task_struct *p) | ||
2765 | { | ||
2766 | return task_has_perm(current, p, PROCESS__GETSCHED); | ||
2767 | } | ||
2768 | |||
2645 | static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim) | 2769 | static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim) |
2646 | { | 2770 | { |
2647 | struct rlimit *old_rlim = current->signal->rlim + resource; | 2771 | struct rlimit *old_rlim = current->signal->rlim + resource; |
@@ -2671,12 +2795,19 @@ static int selinux_task_getscheduler(struct task_struct *p) | |||
2671 | return task_has_perm(current, p, PROCESS__GETSCHED); | 2795 | return task_has_perm(current, p, PROCESS__GETSCHED); |
2672 | } | 2796 | } |
2673 | 2797 | ||
2674 | static int selinux_task_kill(struct task_struct *p, struct siginfo *info, int sig) | 2798 | static int selinux_task_movememory(struct task_struct *p) |
2799 | { | ||
2800 | return task_has_perm(current, p, PROCESS__SETSCHED); | ||
2801 | } | ||
2802 | |||
2803 | static int selinux_task_kill(struct task_struct *p, struct siginfo *info, | ||
2804 | int sig, u32 secid) | ||
2675 | { | 2805 | { |
2676 | u32 perm; | 2806 | u32 perm; |
2677 | int rc; | 2807 | int rc; |
2808 | struct task_security_struct *tsec; | ||
2678 | 2809 | ||
2679 | rc = secondary_ops->task_kill(p, info, sig); | 2810 | rc = secondary_ops->task_kill(p, info, sig, secid); |
2680 | if (rc) | 2811 | if (rc) |
2681 | return rc; | 2812 | return rc; |
2682 | 2813 | ||
@@ -2687,8 +2818,12 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info, int si | |||
2687 | perm = PROCESS__SIGNULL; /* null signal; existence test */ | 2818 | perm = PROCESS__SIGNULL; /* null signal; existence test */ |
2688 | else | 2819 | else |
2689 | perm = signal_to_av(sig); | 2820 | perm = signal_to_av(sig); |
2690 | 2821 | tsec = p->security; | |
2691 | return task_has_perm(current, p, perm); | 2822 | if (secid) |
2823 | rc = avc_has_perm(secid, tsec->sid, SECCLASS_PROCESS, perm, NULL); | ||
2824 | else | ||
2825 | rc = task_has_perm(current, p, perm); | ||
2826 | return rc; | ||
2692 | } | 2827 | } |
2693 | 2828 | ||
2694 | static int selinux_task_prctl(int option, | 2829 | static int selinux_task_prctl(int option, |
@@ -2913,12 +3048,14 @@ static int selinux_socket_create(int family, int type, | |||
2913 | { | 3048 | { |
2914 | int err = 0; | 3049 | int err = 0; |
2915 | struct task_security_struct *tsec; | 3050 | struct task_security_struct *tsec; |
3051 | u32 newsid; | ||
2916 | 3052 | ||
2917 | if (kern) | 3053 | if (kern) |
2918 | goto out; | 3054 | goto out; |
2919 | 3055 | ||
2920 | tsec = current->security; | 3056 | tsec = current->security; |
2921 | err = avc_has_perm(tsec->sid, tsec->sid, | 3057 | newsid = tsec->sockcreate_sid ? : tsec->sid; |
3058 | err = avc_has_perm(tsec->sid, newsid, | ||
2922 | socket_type_to_security_class(family, type, | 3059 | socket_type_to_security_class(family, type, |
2923 | protocol), SOCKET__CREATE, NULL); | 3060 | protocol), SOCKET__CREATE, NULL); |
2924 | 3061 | ||
@@ -2931,12 +3068,14 @@ static void selinux_socket_post_create(struct socket *sock, int family, | |||
2931 | { | 3068 | { |
2932 | struct inode_security_struct *isec; | 3069 | struct inode_security_struct *isec; |
2933 | struct task_security_struct *tsec; | 3070 | struct task_security_struct *tsec; |
3071 | u32 newsid; | ||
2934 | 3072 | ||
2935 | isec = SOCK_INODE(sock)->i_security; | 3073 | isec = SOCK_INODE(sock)->i_security; |
2936 | 3074 | ||
2937 | tsec = current->security; | 3075 | tsec = current->security; |
3076 | newsid = tsec->sockcreate_sid ? : tsec->sid; | ||
2938 | isec->sclass = socket_type_to_security_class(family, type, protocol); | 3077 | isec->sclass = socket_type_to_security_class(family, type, protocol); |
2939 | isec->sid = kern ? SECINITSID_KERNEL : tsec->sid; | 3078 | isec->sid = kern ? SECINITSID_KERNEL : newsid; |
2940 | isec->initialized = 1; | 3079 | isec->initialized = 1; |
2941 | 3080 | ||
2942 | return; | 3081 | return; |
@@ -3214,47 +3353,17 @@ static int selinux_socket_unix_may_send(struct socket *sock, | |||
3214 | return 0; | 3353 | return 0; |
3215 | } | 3354 | } |
3216 | 3355 | ||
3217 | static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | 3356 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, |
3357 | struct avc_audit_data *ad, u32 sock_sid, u16 sock_class, | ||
3358 | u16 family, char *addrp, int len) | ||
3218 | { | 3359 | { |
3219 | u16 family; | 3360 | int err = 0; |
3220 | char *addrp; | ||
3221 | int len, err = 0; | ||
3222 | u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0; | 3361 | u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0; |
3223 | u32 sock_sid = 0; | ||
3224 | u16 sock_class = 0; | ||
3225 | struct socket *sock; | ||
3226 | struct net_device *dev; | ||
3227 | struct avc_audit_data ad; | ||
3228 | 3362 | ||
3229 | family = sk->sk_family; | 3363 | if (!skb->dev) |
3230 | if (family != PF_INET && family != PF_INET6) | ||
3231 | goto out; | 3364 | goto out; |
3232 | 3365 | ||
3233 | /* Handle mapped IPv4 packets arriving via IPv6 sockets */ | 3366 | err = sel_netif_sids(skb->dev, &if_sid, NULL); |
3234 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | ||
3235 | family = PF_INET; | ||
3236 | |||
3237 | read_lock_bh(&sk->sk_callback_lock); | ||
3238 | sock = sk->sk_socket; | ||
3239 | if (sock) { | ||
3240 | struct inode *inode; | ||
3241 | inode = SOCK_INODE(sock); | ||
3242 | if (inode) { | ||
3243 | struct inode_security_struct *isec; | ||
3244 | isec = inode->i_security; | ||
3245 | sock_sid = isec->sid; | ||
3246 | sock_class = isec->sclass; | ||
3247 | } | ||
3248 | } | ||
3249 | read_unlock_bh(&sk->sk_callback_lock); | ||
3250 | if (!sock_sid) | ||
3251 | goto out; | ||
3252 | |||
3253 | dev = skb->dev; | ||
3254 | if (!dev) | ||
3255 | goto out; | ||
3256 | |||
3257 | err = sel_netif_sids(dev, &if_sid, NULL); | ||
3258 | if (err) | 3367 | if (err) |
3259 | goto out; | 3368 | goto out; |
3260 | 3369 | ||
@@ -3277,44 +3386,88 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
3277 | break; | 3386 | break; |
3278 | } | 3387 | } |
3279 | 3388 | ||
3280 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3389 | err = avc_has_perm(sock_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); |
3281 | ad.u.net.netif = dev->name; | ||
3282 | ad.u.net.family = family; | ||
3283 | |||
3284 | err = selinux_parse_skb(skb, &ad, &addrp, &len, 1); | ||
3285 | if (err) | ||
3286 | goto out; | ||
3287 | |||
3288 | err = avc_has_perm(sock_sid, if_sid, SECCLASS_NETIF, netif_perm, &ad); | ||
3289 | if (err) | 3390 | if (err) |
3290 | goto out; | 3391 | goto out; |
3291 | 3392 | ||
3292 | /* Fixme: this lookup is inefficient */ | ||
3293 | err = security_node_sid(family, addrp, len, &node_sid); | 3393 | err = security_node_sid(family, addrp, len, &node_sid); |
3294 | if (err) | 3394 | if (err) |
3295 | goto out; | 3395 | goto out; |
3296 | 3396 | ||
3297 | err = avc_has_perm(sock_sid, node_sid, SECCLASS_NODE, node_perm, &ad); | 3397 | err = avc_has_perm(sock_sid, node_sid, SECCLASS_NODE, node_perm, ad); |
3298 | if (err) | 3398 | if (err) |
3299 | goto out; | 3399 | goto out; |
3300 | 3400 | ||
3301 | if (recv_perm) { | 3401 | if (recv_perm) { |
3302 | u32 port_sid; | 3402 | u32 port_sid; |
3303 | 3403 | ||
3304 | /* Fixme: make this more efficient */ | ||
3305 | err = security_port_sid(sk->sk_family, sk->sk_type, | 3404 | err = security_port_sid(sk->sk_family, sk->sk_type, |
3306 | sk->sk_protocol, ntohs(ad.u.net.sport), | 3405 | sk->sk_protocol, ntohs(ad->u.net.sport), |
3307 | &port_sid); | 3406 | &port_sid); |
3308 | if (err) | 3407 | if (err) |
3309 | goto out; | 3408 | goto out; |
3310 | 3409 | ||
3311 | err = avc_has_perm(sock_sid, port_sid, | 3410 | err = avc_has_perm(sock_sid, port_sid, |
3312 | sock_class, recv_perm, &ad); | 3411 | sock_class, recv_perm, ad); |
3313 | } | 3412 | } |
3314 | 3413 | ||
3315 | if (!err) | 3414 | out: |
3316 | err = selinux_xfrm_sock_rcv_skb(sock_sid, skb); | 3415 | return err; |
3416 | } | ||
3417 | |||
3418 | static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | ||
3419 | { | ||
3420 | u16 family; | ||
3421 | u16 sock_class = 0; | ||
3422 | char *addrp; | ||
3423 | int len, err = 0; | ||
3424 | u32 sock_sid = 0; | ||
3425 | struct socket *sock; | ||
3426 | struct avc_audit_data ad; | ||
3427 | |||
3428 | family = sk->sk_family; | ||
3429 | if (family != PF_INET && family != PF_INET6) | ||
3430 | goto out; | ||
3431 | |||
3432 | /* Handle mapped IPv4 packets arriving via IPv6 sockets */ | ||
3433 | if (family == PF_INET6 && skb->protocol == ntohs(ETH_P_IP)) | ||
3434 | family = PF_INET; | ||
3435 | |||
3436 | read_lock_bh(&sk->sk_callback_lock); | ||
3437 | sock = sk->sk_socket; | ||
3438 | if (sock) { | ||
3439 | struct inode *inode; | ||
3440 | inode = SOCK_INODE(sock); | ||
3441 | if (inode) { | ||
3442 | struct inode_security_struct *isec; | ||
3443 | isec = inode->i_security; | ||
3444 | sock_sid = isec->sid; | ||
3445 | sock_class = isec->sclass; | ||
3446 | } | ||
3447 | } | ||
3448 | read_unlock_bh(&sk->sk_callback_lock); | ||
3449 | if (!sock_sid) | ||
3450 | goto out; | ||
3451 | |||
3452 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
3453 | ad.u.net.netif = skb->dev ? skb->dev->name : "[unknown]"; | ||
3454 | ad.u.net.family = family; | ||
3455 | |||
3456 | err = selinux_parse_skb(skb, &ad, &addrp, &len, 1); | ||
3457 | if (err) | ||
3458 | goto out; | ||
3317 | 3459 | ||
3460 | if (selinux_compat_net) | ||
3461 | err = selinux_sock_rcv_skb_compat(sk, skb, &ad, sock_sid, | ||
3462 | sock_class, family, | ||
3463 | addrp, len); | ||
3464 | else | ||
3465 | err = avc_has_perm(sock_sid, skb->secmark, SECCLASS_PACKET, | ||
3466 | PACKET__RECV, &ad); | ||
3467 | if (err) | ||
3468 | goto out; | ||
3469 | |||
3470 | err = selinux_xfrm_sock_rcv_skb(sock_sid, skb); | ||
3318 | out: | 3471 | out: |
3319 | return err; | 3472 | return err; |
3320 | } | 3473 | } |
@@ -3374,7 +3527,13 @@ out: | |||
3374 | static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, u32 *seclen) | 3527 | static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, u32 *seclen) |
3375 | { | 3528 | { |
3376 | int err = 0; | 3529 | int err = 0; |
3377 | u32 peer_sid = selinux_socket_getpeer_dgram(skb); | 3530 | u32 peer_sid; |
3531 | |||
3532 | if (skb->sk->sk_family == PF_UNIX) | ||
3533 | selinux_get_inode_sid(SOCK_INODE(skb->sk->sk_socket), | ||
3534 | &peer_sid); | ||
3535 | else | ||
3536 | peer_sid = selinux_socket_getpeer_dgram(skb); | ||
3378 | 3537 | ||
3379 | if (peer_sid == SECSID_NULL) | 3538 | if (peer_sid == SECSID_NULL) |
3380 | return -EINVAL; | 3539 | return -EINVAL; |
@@ -3386,8 +3545,6 @@ static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, | |||
3386 | return 0; | 3545 | return 0; |
3387 | } | 3546 | } |
3388 | 3547 | ||
3389 | |||
3390 | |||
3391 | static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority) | 3548 | static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority) |
3392 | { | 3549 | { |
3393 | return sk_alloc_security(sk, family, priority); | 3550 | return sk_alloc_security(sk, family, priority); |
@@ -3454,42 +3611,18 @@ out: | |||
3454 | 3611 | ||
3455 | #ifdef CONFIG_NETFILTER | 3612 | #ifdef CONFIG_NETFILTER |
3456 | 3613 | ||
3457 | static unsigned int selinux_ip_postroute_last(unsigned int hooknum, | 3614 | static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device *dev, |
3458 | struct sk_buff **pskb, | 3615 | struct inode_security_struct *isec, |
3459 | const struct net_device *in, | 3616 | struct avc_audit_data *ad, |
3460 | const struct net_device *out, | 3617 | u16 family, char *addrp, int len) |
3461 | int (*okfn)(struct sk_buff *), | ||
3462 | u16 family) | ||
3463 | { | 3618 | { |
3464 | char *addrp; | 3619 | int err; |
3465 | int len, err = NF_ACCEPT; | ||
3466 | u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0; | 3620 | u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0; |
3467 | struct sock *sk; | ||
3468 | struct socket *sock; | ||
3469 | struct inode *inode; | ||
3470 | struct sk_buff *skb = *pskb; | ||
3471 | struct inode_security_struct *isec; | ||
3472 | struct avc_audit_data ad; | ||
3473 | struct net_device *dev = (struct net_device *)out; | ||
3474 | 3621 | ||
3475 | sk = skb->sk; | ||
3476 | if (!sk) | ||
3477 | goto out; | ||
3478 | |||
3479 | sock = sk->sk_socket; | ||
3480 | if (!sock) | ||
3481 | goto out; | ||
3482 | |||
3483 | inode = SOCK_INODE(sock); | ||
3484 | if (!inode) | ||
3485 | goto out; | ||
3486 | |||
3487 | err = sel_netif_sids(dev, &if_sid, NULL); | 3622 | err = sel_netif_sids(dev, &if_sid, NULL); |
3488 | if (err) | 3623 | if (err) |
3489 | goto out; | 3624 | goto out; |
3490 | 3625 | ||
3491 | isec = inode->i_security; | ||
3492 | |||
3493 | switch (isec->sclass) { | 3626 | switch (isec->sclass) { |
3494 | case SECCLASS_UDP_SOCKET: | 3627 | case SECCLASS_UDP_SOCKET: |
3495 | netif_perm = NETIF__UDP_SEND; | 3628 | netif_perm = NETIF__UDP_SEND; |
@@ -3509,55 +3642,88 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum, | |||
3509 | break; | 3642 | break; |
3510 | } | 3643 | } |
3511 | 3644 | ||
3512 | 3645 | err = avc_has_perm(isec->sid, if_sid, SECCLASS_NETIF, netif_perm, ad); | |
3513 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3646 | if (err) |
3514 | ad.u.net.netif = dev->name; | ||
3515 | ad.u.net.family = family; | ||
3516 | |||
3517 | err = selinux_parse_skb(skb, &ad, &addrp, | ||
3518 | &len, 0) ? NF_DROP : NF_ACCEPT; | ||
3519 | if (err != NF_ACCEPT) | ||
3520 | goto out; | ||
3521 | |||
3522 | err = avc_has_perm(isec->sid, if_sid, SECCLASS_NETIF, | ||
3523 | netif_perm, &ad) ? NF_DROP : NF_ACCEPT; | ||
3524 | if (err != NF_ACCEPT) | ||
3525 | goto out; | 3647 | goto out; |
3526 | 3648 | ||
3527 | /* Fixme: this lookup is inefficient */ | 3649 | err = security_node_sid(family, addrp, len, &node_sid); |
3528 | err = security_node_sid(family, addrp, len, | 3650 | if (err) |
3529 | &node_sid) ? NF_DROP : NF_ACCEPT; | ||
3530 | if (err != NF_ACCEPT) | ||
3531 | goto out; | 3651 | goto out; |
3532 | 3652 | ||
3533 | err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE, | 3653 | err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE, node_perm, ad); |
3534 | node_perm, &ad) ? NF_DROP : NF_ACCEPT; | 3654 | if (err) |
3535 | if (err != NF_ACCEPT) | ||
3536 | goto out; | 3655 | goto out; |
3537 | 3656 | ||
3538 | if (send_perm) { | 3657 | if (send_perm) { |
3539 | u32 port_sid; | 3658 | u32 port_sid; |
3540 | 3659 | ||
3541 | /* Fixme: make this more efficient */ | ||
3542 | err = security_port_sid(sk->sk_family, | 3660 | err = security_port_sid(sk->sk_family, |
3543 | sk->sk_type, | 3661 | sk->sk_type, |
3544 | sk->sk_protocol, | 3662 | sk->sk_protocol, |
3545 | ntohs(ad.u.net.dport), | 3663 | ntohs(ad->u.net.dport), |
3546 | &port_sid) ? NF_DROP : NF_ACCEPT; | 3664 | &port_sid); |
3547 | if (err != NF_ACCEPT) | 3665 | if (err) |
3548 | goto out; | 3666 | goto out; |
3549 | 3667 | ||
3550 | err = avc_has_perm(isec->sid, port_sid, isec->sclass, | 3668 | err = avc_has_perm(isec->sid, port_sid, isec->sclass, |
3551 | send_perm, &ad) ? NF_DROP : NF_ACCEPT; | 3669 | send_perm, ad); |
3552 | } | 3670 | } |
3671 | out: | ||
3672 | return err; | ||
3673 | } | ||
3674 | |||
3675 | static unsigned int selinux_ip_postroute_last(unsigned int hooknum, | ||
3676 | struct sk_buff **pskb, | ||
3677 | const struct net_device *in, | ||
3678 | const struct net_device *out, | ||
3679 | int (*okfn)(struct sk_buff *), | ||
3680 | u16 family) | ||
3681 | { | ||
3682 | char *addrp; | ||
3683 | int len, err = 0; | ||
3684 | struct sock *sk; | ||
3685 | struct socket *sock; | ||
3686 | struct inode *inode; | ||
3687 | struct sk_buff *skb = *pskb; | ||
3688 | struct inode_security_struct *isec; | ||
3689 | struct avc_audit_data ad; | ||
3690 | struct net_device *dev = (struct net_device *)out; | ||
3553 | 3691 | ||
3554 | if (err != NF_ACCEPT) | 3692 | sk = skb->sk; |
3693 | if (!sk) | ||
3555 | goto out; | 3694 | goto out; |
3556 | 3695 | ||
3557 | err = selinux_xfrm_postroute_last(isec->sid, skb); | 3696 | sock = sk->sk_socket; |
3697 | if (!sock) | ||
3698 | goto out; | ||
3699 | |||
3700 | inode = SOCK_INODE(sock); | ||
3701 | if (!inode) | ||
3702 | goto out; | ||
3703 | |||
3704 | isec = inode->i_security; | ||
3705 | |||
3706 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
3707 | ad.u.net.netif = dev->name; | ||
3708 | ad.u.net.family = family; | ||
3558 | 3709 | ||
3710 | err = selinux_parse_skb(skb, &ad, &addrp, &len, 0); | ||
3711 | if (err) | ||
3712 | goto out; | ||
3713 | |||
3714 | if (selinux_compat_net) | ||
3715 | err = selinux_ip_postroute_last_compat(sk, dev, isec, &ad, | ||
3716 | family, addrp, len); | ||
3717 | else | ||
3718 | err = avc_has_perm(isec->sid, skb->secmark, SECCLASS_PACKET, | ||
3719 | PACKET__SEND, &ad); | ||
3720 | |||
3721 | if (err) | ||
3722 | goto out; | ||
3723 | |||
3724 | err = selinux_xfrm_postroute_last(isec->sid, skb); | ||
3559 | out: | 3725 | out: |
3560 | return err; | 3726 | return err ? NF_DROP : NF_ACCEPT; |
3561 | } | 3727 | } |
3562 | 3728 | ||
3563 | static unsigned int selinux_ipv4_postroute_last(unsigned int hooknum, | 3729 | static unsigned int selinux_ipv4_postroute_last(unsigned int hooknum, |
@@ -3586,32 +3752,32 @@ static unsigned int selinux_ipv6_postroute_last(unsigned int hooknum, | |||
3586 | 3752 | ||
3587 | static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) | 3753 | static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) |
3588 | { | 3754 | { |
3589 | struct task_security_struct *tsec; | ||
3590 | struct av_decision avd; | ||
3591 | int err; | 3755 | int err; |
3592 | 3756 | ||
3593 | err = secondary_ops->netlink_send(sk, skb); | 3757 | err = secondary_ops->netlink_send(sk, skb); |
3594 | if (err) | 3758 | if (err) |
3595 | return err; | 3759 | return err; |
3596 | 3760 | ||
3597 | tsec = current->security; | ||
3598 | |||
3599 | avd.allowed = 0; | ||
3600 | avc_has_perm_noaudit(tsec->sid, tsec->sid, | ||
3601 | SECCLASS_CAPABILITY, ~0, &avd); | ||
3602 | cap_mask(NETLINK_CB(skb).eff_cap, avd.allowed); | ||
3603 | |||
3604 | if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS) | 3761 | if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS) |
3605 | err = selinux_nlmsg_perm(sk, skb); | 3762 | err = selinux_nlmsg_perm(sk, skb); |
3606 | 3763 | ||
3607 | return err; | 3764 | return err; |
3608 | } | 3765 | } |
3609 | 3766 | ||
3610 | static int selinux_netlink_recv(struct sk_buff *skb) | 3767 | static int selinux_netlink_recv(struct sk_buff *skb, int capability) |
3611 | { | 3768 | { |
3612 | if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) | 3769 | int err; |
3613 | return -EPERM; | 3770 | struct avc_audit_data ad; |
3614 | return 0; | 3771 | |
3772 | err = secondary_ops->netlink_recv(skb, capability); | ||
3773 | if (err) | ||
3774 | return err; | ||
3775 | |||
3776 | AVC_AUDIT_DATA_INIT(&ad, CAP); | ||
3777 | ad.u.cap = capability; | ||
3778 | |||
3779 | return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid, | ||
3780 | SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad); | ||
3615 | } | 3781 | } |
3616 | 3782 | ||
3617 | static int ipc_alloc_security(struct task_struct *task, | 3783 | static int ipc_alloc_security(struct task_struct *task, |
@@ -4114,6 +4280,10 @@ static int selinux_getprocattr(struct task_struct *p, | |||
4114 | sid = tsec->exec_sid; | 4280 | sid = tsec->exec_sid; |
4115 | else if (!strcmp(name, "fscreate")) | 4281 | else if (!strcmp(name, "fscreate")) |
4116 | sid = tsec->create_sid; | 4282 | sid = tsec->create_sid; |
4283 | else if (!strcmp(name, "keycreate")) | ||
4284 | sid = tsec->keycreate_sid; | ||
4285 | else if (!strcmp(name, "sockcreate")) | ||
4286 | sid = tsec->sockcreate_sid; | ||
4117 | else | 4287 | else |
4118 | return -EINVAL; | 4288 | return -EINVAL; |
4119 | 4289 | ||
@@ -4146,6 +4316,10 @@ static int selinux_setprocattr(struct task_struct *p, | |||
4146 | error = task_has_perm(current, p, PROCESS__SETEXEC); | 4316 | error = task_has_perm(current, p, PROCESS__SETEXEC); |
4147 | else if (!strcmp(name, "fscreate")) | 4317 | else if (!strcmp(name, "fscreate")) |
4148 | error = task_has_perm(current, p, PROCESS__SETFSCREATE); | 4318 | error = task_has_perm(current, p, PROCESS__SETFSCREATE); |
4319 | else if (!strcmp(name, "keycreate")) | ||
4320 | error = task_has_perm(current, p, PROCESS__SETKEYCREATE); | ||
4321 | else if (!strcmp(name, "sockcreate")) | ||
4322 | error = task_has_perm(current, p, PROCESS__SETSOCKCREATE); | ||
4149 | else if (!strcmp(name, "current")) | 4323 | else if (!strcmp(name, "current")) |
4150 | error = task_has_perm(current, p, PROCESS__SETCURRENT); | 4324 | error = task_has_perm(current, p, PROCESS__SETCURRENT); |
4151 | else | 4325 | else |
@@ -4175,6 +4349,13 @@ static int selinux_setprocattr(struct task_struct *p, | |||
4175 | tsec->exec_sid = sid; | 4349 | tsec->exec_sid = sid; |
4176 | else if (!strcmp(name, "fscreate")) | 4350 | else if (!strcmp(name, "fscreate")) |
4177 | tsec->create_sid = sid; | 4351 | tsec->create_sid = sid; |
4352 | else if (!strcmp(name, "keycreate")) { | ||
4353 | error = may_create_key(sid, p); | ||
4354 | if (error) | ||
4355 | return error; | ||
4356 | tsec->keycreate_sid = sid; | ||
4357 | } else if (!strcmp(name, "sockcreate")) | ||
4358 | tsec->sockcreate_sid = sid; | ||
4178 | else if (!strcmp(name, "current")) { | 4359 | else if (!strcmp(name, "current")) { |
4179 | struct av_decision avd; | 4360 | struct av_decision avd; |
4180 | 4361 | ||
@@ -4226,6 +4407,61 @@ static int selinux_setprocattr(struct task_struct *p, | |||
4226 | return size; | 4407 | return size; |
4227 | } | 4408 | } |
4228 | 4409 | ||
4410 | #ifdef CONFIG_KEYS | ||
4411 | |||
4412 | static int selinux_key_alloc(struct key *k, struct task_struct *tsk, | ||
4413 | unsigned long flags) | ||
4414 | { | ||
4415 | struct task_security_struct *tsec = tsk->security; | ||
4416 | struct key_security_struct *ksec; | ||
4417 | |||
4418 | ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL); | ||
4419 | if (!ksec) | ||
4420 | return -ENOMEM; | ||
4421 | |||
4422 | ksec->obj = k; | ||
4423 | if (tsec->keycreate_sid) | ||
4424 | ksec->sid = tsec->keycreate_sid; | ||
4425 | else | ||
4426 | ksec->sid = tsec->sid; | ||
4427 | k->security = ksec; | ||
4428 | |||
4429 | return 0; | ||
4430 | } | ||
4431 | |||
4432 | static void selinux_key_free(struct key *k) | ||
4433 | { | ||
4434 | struct key_security_struct *ksec = k->security; | ||
4435 | |||
4436 | k->security = NULL; | ||
4437 | kfree(ksec); | ||
4438 | } | ||
4439 | |||
4440 | static int selinux_key_permission(key_ref_t key_ref, | ||
4441 | struct task_struct *ctx, | ||
4442 | key_perm_t perm) | ||
4443 | { | ||
4444 | struct key *key; | ||
4445 | struct task_security_struct *tsec; | ||
4446 | struct key_security_struct *ksec; | ||
4447 | |||
4448 | key = key_ref_to_ptr(key_ref); | ||
4449 | |||
4450 | tsec = ctx->security; | ||
4451 | ksec = key->security; | ||
4452 | |||
4453 | /* if no specific permissions are requested, we skip the | ||
4454 | permission check. No serious, additional covert channels | ||
4455 | appear to be created. */ | ||
4456 | if (perm == 0) | ||
4457 | return 0; | ||
4458 | |||
4459 | return avc_has_perm(tsec->sid, ksec->sid, | ||
4460 | SECCLASS_KEY, perm, NULL); | ||
4461 | } | ||
4462 | |||
4463 | #endif | ||
4464 | |||
4229 | static struct security_operations selinux_ops = { | 4465 | static struct security_operations selinux_ops = { |
4230 | .ptrace = selinux_ptrace, | 4466 | .ptrace = selinux_ptrace, |
4231 | .capget = selinux_capget, | 4467 | .capget = selinux_capget, |
@@ -4304,11 +4540,15 @@ static struct security_operations selinux_ops = { | |||
4304 | .task_setpgid = selinux_task_setpgid, | 4540 | .task_setpgid = selinux_task_setpgid, |
4305 | .task_getpgid = selinux_task_getpgid, | 4541 | .task_getpgid = selinux_task_getpgid, |
4306 | .task_getsid = selinux_task_getsid, | 4542 | .task_getsid = selinux_task_getsid, |
4543 | .task_getsecid = selinux_task_getsecid, | ||
4307 | .task_setgroups = selinux_task_setgroups, | 4544 | .task_setgroups = selinux_task_setgroups, |
4308 | .task_setnice = selinux_task_setnice, | 4545 | .task_setnice = selinux_task_setnice, |
4546 | .task_setioprio = selinux_task_setioprio, | ||
4547 | .task_getioprio = selinux_task_getioprio, | ||
4309 | .task_setrlimit = selinux_task_setrlimit, | 4548 | .task_setrlimit = selinux_task_setrlimit, |
4310 | .task_setscheduler = selinux_task_setscheduler, | 4549 | .task_setscheduler = selinux_task_setscheduler, |
4311 | .task_getscheduler = selinux_task_getscheduler, | 4550 | .task_getscheduler = selinux_task_getscheduler, |
4551 | .task_movememory = selinux_task_movememory, | ||
4312 | .task_kill = selinux_task_kill, | 4552 | .task_kill = selinux_task_kill, |
4313 | .task_wait = selinux_task_wait, | 4553 | .task_wait = selinux_task_wait, |
4314 | .task_prctl = selinux_task_prctl, | 4554 | .task_prctl = selinux_task_prctl, |
@@ -4374,10 +4614,18 @@ static struct security_operations selinux_ops = { | |||
4374 | .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, | 4614 | .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, |
4375 | .xfrm_policy_clone_security = selinux_xfrm_policy_clone, | 4615 | .xfrm_policy_clone_security = selinux_xfrm_policy_clone, |
4376 | .xfrm_policy_free_security = selinux_xfrm_policy_free, | 4616 | .xfrm_policy_free_security = selinux_xfrm_policy_free, |
4617 | .xfrm_policy_delete_security = selinux_xfrm_policy_delete, | ||
4377 | .xfrm_state_alloc_security = selinux_xfrm_state_alloc, | 4618 | .xfrm_state_alloc_security = selinux_xfrm_state_alloc, |
4378 | .xfrm_state_free_security = selinux_xfrm_state_free, | 4619 | .xfrm_state_free_security = selinux_xfrm_state_free, |
4620 | .xfrm_state_delete_security = selinux_xfrm_state_delete, | ||
4379 | .xfrm_policy_lookup = selinux_xfrm_policy_lookup, | 4621 | .xfrm_policy_lookup = selinux_xfrm_policy_lookup, |
4380 | #endif | 4622 | #endif |
4623 | |||
4624 | #ifdef CONFIG_KEYS | ||
4625 | .key_alloc = selinux_key_alloc, | ||
4626 | .key_free = selinux_key_free, | ||
4627 | .key_permission = selinux_key_permission, | ||
4628 | #endif | ||
4381 | }; | 4629 | }; |
4382 | 4630 | ||
4383 | static __init int selinux_init(void) | 4631 | static __init int selinux_init(void) |
@@ -4413,6 +4661,15 @@ static __init int selinux_init(void) | |||
4413 | } else { | 4661 | } else { |
4414 | printk(KERN_INFO "SELinux: Starting in permissive mode\n"); | 4662 | printk(KERN_INFO "SELinux: Starting in permissive mode\n"); |
4415 | } | 4663 | } |
4664 | |||
4665 | #ifdef CONFIG_KEYS | ||
4666 | /* Add security information to initial keyrings */ | ||
4667 | selinux_key_alloc(&root_user_keyring, current, | ||
4668 | KEY_ALLOC_NOT_IN_QUOTA); | ||
4669 | selinux_key_alloc(&root_session_keyring, current, | ||
4670 | KEY_ALLOC_NOT_IN_QUOTA); | ||
4671 | #endif | ||
4672 | |||
4416 | return 0; | 4673 | return 0; |
4417 | } | 4674 | } |
4418 | 4675 | ||
@@ -4422,6 +4679,7 @@ void selinux_complete_init(void) | |||
4422 | 4679 | ||
4423 | /* Set up any superblocks initialized prior to the policy load. */ | 4680 | /* Set up any superblocks initialized prior to the policy load. */ |
4424 | printk(KERN_INFO "SELinux: Setting up existing superblocks.\n"); | 4681 | printk(KERN_INFO "SELinux: Setting up existing superblocks.\n"); |
4682 | spin_lock(&sb_lock); | ||
4425 | spin_lock(&sb_security_lock); | 4683 | spin_lock(&sb_security_lock); |
4426 | next_sb: | 4684 | next_sb: |
4427 | if (!list_empty(&superblock_security_head)) { | 4685 | if (!list_empty(&superblock_security_head)) { |
@@ -4430,19 +4688,20 @@ next_sb: | |||
4430 | struct superblock_security_struct, | 4688 | struct superblock_security_struct, |
4431 | list); | 4689 | list); |
4432 | struct super_block *sb = sbsec->sb; | 4690 | struct super_block *sb = sbsec->sb; |
4433 | spin_lock(&sb_lock); | ||
4434 | sb->s_count++; | 4691 | sb->s_count++; |
4435 | spin_unlock(&sb_lock); | ||
4436 | spin_unlock(&sb_security_lock); | 4692 | spin_unlock(&sb_security_lock); |
4693 | spin_unlock(&sb_lock); | ||
4437 | down_read(&sb->s_umount); | 4694 | down_read(&sb->s_umount); |
4438 | if (sb->s_root) | 4695 | if (sb->s_root) |
4439 | superblock_doinit(sb, NULL); | 4696 | superblock_doinit(sb, NULL); |
4440 | drop_super(sb); | 4697 | drop_super(sb); |
4698 | spin_lock(&sb_lock); | ||
4441 | spin_lock(&sb_security_lock); | 4699 | spin_lock(&sb_security_lock); |
4442 | list_del_init(&sbsec->list); | 4700 | list_del_init(&sbsec->list); |
4443 | goto next_sb; | 4701 | goto next_sb; |
4444 | } | 4702 | } |
4445 | spin_unlock(&sb_security_lock); | 4703 | spin_unlock(&sb_security_lock); |
4704 | spin_unlock(&sb_lock); | ||
4446 | } | 4705 | } |
4447 | 4706 | ||
4448 | /* SELinux requires early initialization in order to label | 4707 | /* SELinux requires early initialization in order to label |