diff options
| author | Ingo Molnar <mingo@kernel.org> | 2013-12-17 09:27:08 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2013-12-17 09:27:08 -0500 |
| commit | bb799d3b980eb803ca2da4a4eefbd9308f8d988a (patch) | |
| tree | 69fbe0cd6d47b23a50f5e1d87bf7489532fae149 /security/selinux | |
| parent | 919fc6e34831d1c2b58bfb5ae261dc3facc9b269 (diff) | |
| parent | 319e2e3f63c348a9b66db4667efa73178e18b17d (diff) | |
Merge tag 'v3.13-rc4' into core/locking
Merge Linux 3.13-rc4, to refresh this rather old tree with the latest fixes.
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'security/selinux')
| -rw-r--r-- | security/selinux/hooks.c | 241 | ||||
| -rw-r--r-- | security/selinux/include/objsec.h | 4 | ||||
| -rw-r--r-- | security/selinux/include/security.h | 13 | ||||
| -rw-r--r-- | security/selinux/include/xfrm.h | 49 | ||||
| -rw-r--r-- | security/selinux/netlabel.c | 6 | ||||
| -rw-r--r-- | security/selinux/netnode.c | 2 | ||||
| -rw-r--r-- | security/selinux/nlmsgtab.c | 2 | ||||
| -rw-r--r-- | security/selinux/selinuxfs.c | 4 | ||||
| -rw-r--r-- | security/selinux/ss/ebitmap.c | 20 | ||||
| -rw-r--r-- | security/selinux/ss/ebitmap.h | 10 | ||||
| -rw-r--r-- | security/selinux/ss/mls.c | 22 | ||||
| -rw-r--r-- | security/selinux/ss/mls_types.h | 2 | ||||
| -rw-r--r-- | security/selinux/ss/policydb.c | 3 | ||||
| -rw-r--r-- | security/selinux/ss/services.c | 24 | ||||
| -rw-r--r-- | security/selinux/xfrm.c | 481 |
15 files changed, 504 insertions, 379 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c540795fb3f2..419491d8e7d2 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -53,6 +53,7 @@ | |||
| 53 | #include <net/ip.h> /* for local_port_range[] */ | 53 | #include <net/ip.h> /* for local_port_range[] */ |
| 54 | #include <net/sock.h> | 54 | #include <net/sock.h> |
| 55 | #include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */ | 55 | #include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */ |
| 56 | #include <net/inet_connection_sock.h> | ||
| 56 | #include <net/net_namespace.h> | 57 | #include <net/net_namespace.h> |
| 57 | #include <net/netlabel.h> | 58 | #include <net/netlabel.h> |
| 58 | #include <linux/uaccess.h> | 59 | #include <linux/uaccess.h> |
| @@ -95,8 +96,6 @@ | |||
| 95 | #include "audit.h" | 96 | #include "audit.h" |
| 96 | #include "avc_ss.h" | 97 | #include "avc_ss.h" |
| 97 | 98 | ||
| 98 | #define NUM_SEL_MNT_OPTS 5 | ||
| 99 | |||
| 100 | extern struct security_operations *security_ops; | 99 | extern struct security_operations *security_ops; |
| 101 | 100 | ||
| 102 | /* SECMARK reference count */ | 101 | /* SECMARK reference count */ |
| @@ -139,12 +138,28 @@ static struct kmem_cache *sel_inode_cache; | |||
| 139 | * This function checks the SECMARK reference counter to see if any SECMARK | 138 | * This function checks the SECMARK reference counter to see if any SECMARK |
| 140 | * targets are currently configured, if the reference counter is greater than | 139 | * targets are currently configured, if the reference counter is greater than |
| 141 | * zero SECMARK is considered to be enabled. Returns true (1) if SECMARK is | 140 | * zero SECMARK is considered to be enabled. Returns true (1) if SECMARK is |
| 142 | * enabled, false (0) if SECMARK is disabled. | 141 | * enabled, false (0) if SECMARK is disabled. If the always_check_network |
| 142 | * policy capability is enabled, SECMARK is always considered enabled. | ||
| 143 | * | 143 | * |
| 144 | */ | 144 | */ |
| 145 | static int selinux_secmark_enabled(void) | 145 | static int selinux_secmark_enabled(void) |
| 146 | { | 146 | { |
| 147 | return (atomic_read(&selinux_secmark_refcount) > 0); | 147 | return (selinux_policycap_alwaysnetwork || atomic_read(&selinux_secmark_refcount)); |
| 148 | } | ||
| 149 | |||
| 150 | /** | ||
| 151 | * selinux_peerlbl_enabled - Check to see if peer labeling is currently enabled | ||
| 152 | * | ||
| 153 | * Description: | ||
| 154 | * This function checks if NetLabel or labeled IPSEC is enabled. Returns true | ||
| 155 | * (1) if any are enabled or false (0) if neither are enabled. If the | ||
| 156 | * always_check_network policy capability is enabled, peer labeling | ||
| 157 | * is always considered enabled. | ||
| 158 | * | ||
| 159 | */ | ||
| 160 | static int selinux_peerlbl_enabled(void) | ||
| 161 | { | ||
| 162 | return (selinux_policycap_alwaysnetwork || netlbl_enabled() || selinux_xfrm_enabled()); | ||
| 148 | } | 163 | } |
| 149 | 164 | ||
| 150 | /* | 165 | /* |
| @@ -309,8 +324,11 @@ enum { | |||
| 309 | Opt_defcontext = 3, | 324 | Opt_defcontext = 3, |
| 310 | Opt_rootcontext = 4, | 325 | Opt_rootcontext = 4, |
| 311 | Opt_labelsupport = 5, | 326 | Opt_labelsupport = 5, |
| 327 | Opt_nextmntopt = 6, | ||
| 312 | }; | 328 | }; |
| 313 | 329 | ||
| 330 | #define NUM_SEL_MNT_OPTS (Opt_nextmntopt - 1) | ||
| 331 | |||
| 314 | static const match_table_t tokens = { | 332 | static const match_table_t tokens = { |
| 315 | {Opt_context, CONTEXT_STR "%s"}, | 333 | {Opt_context, CONTEXT_STR "%s"}, |
| 316 | {Opt_fscontext, FSCONTEXT_STR "%s"}, | 334 | {Opt_fscontext, FSCONTEXT_STR "%s"}, |
| @@ -355,6 +373,29 @@ static int may_context_mount_inode_relabel(u32 sid, | |||
| 355 | return rc; | 373 | return rc; |
| 356 | } | 374 | } |
| 357 | 375 | ||
| 376 | static int selinux_is_sblabel_mnt(struct super_block *sb) | ||
| 377 | { | ||
| 378 | struct superblock_security_struct *sbsec = sb->s_security; | ||
| 379 | |||
| 380 | if (sbsec->behavior == SECURITY_FS_USE_XATTR || | ||
| 381 | sbsec->behavior == SECURITY_FS_USE_TRANS || | ||
| 382 | sbsec->behavior == SECURITY_FS_USE_TASK) | ||
| 383 | return 1; | ||
| 384 | |||
| 385 | /* Special handling for sysfs. Is genfs but also has setxattr handler*/ | ||
| 386 | if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0) | ||
| 387 | return 1; | ||
| 388 | |||
| 389 | /* | ||
| 390 | * Special handling for rootfs. Is genfs but supports | ||
| 391 | * setting SELinux context on in-core inodes. | ||
| 392 | */ | ||
| 393 | if (strncmp(sb->s_type->name, "rootfs", sizeof("rootfs")) == 0) | ||
| 394 | return 1; | ||
| 395 | |||
| 396 | return 0; | ||
| 397 | } | ||
| 398 | |||
| 358 | static int sb_finish_set_opts(struct super_block *sb) | 399 | static int sb_finish_set_opts(struct super_block *sb) |
| 359 | { | 400 | { |
| 360 | struct superblock_security_struct *sbsec = sb->s_security; | 401 | struct superblock_security_struct *sbsec = sb->s_security; |
| @@ -388,8 +429,6 @@ static int sb_finish_set_opts(struct super_block *sb) | |||
| 388 | } | 429 | } |
| 389 | } | 430 | } |
| 390 | 431 | ||
| 391 | sbsec->flags |= (SE_SBINITIALIZED | SE_SBLABELSUPP); | ||
| 392 | |||
| 393 | if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) | 432 | if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) |
| 394 | printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n", | 433 | printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n", |
| 395 | sb->s_id, sb->s_type->name); | 434 | sb->s_id, sb->s_type->name); |
| @@ -398,15 +437,9 @@ static int sb_finish_set_opts(struct super_block *sb) | |||
| 398 | sb->s_id, sb->s_type->name, | 437 | sb->s_id, sb->s_type->name, |
| 399 | labeling_behaviors[sbsec->behavior-1]); | 438 | labeling_behaviors[sbsec->behavior-1]); |
| 400 | 439 | ||
| 401 | if (sbsec->behavior == SECURITY_FS_USE_GENFS || | 440 | sbsec->flags |= SE_SBINITIALIZED; |
| 402 | sbsec->behavior == SECURITY_FS_USE_MNTPOINT || | 441 | if (selinux_is_sblabel_mnt(sb)) |
| 403 | sbsec->behavior == SECURITY_FS_USE_NONE || | 442 | sbsec->flags |= SBLABEL_MNT; |
| 404 | sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) | ||
| 405 | sbsec->flags &= ~SE_SBLABELSUPP; | ||
| 406 | |||
| 407 | /* Special handling for sysfs. Is genfs but also has setxattr handler*/ | ||
| 408 | if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0) | ||
| 409 | sbsec->flags |= SE_SBLABELSUPP; | ||
| 410 | 443 | ||
| 411 | /* Initialize the root inode. */ | 444 | /* Initialize the root inode. */ |
| 412 | rc = inode_doinit_with_dentry(root_inode, root); | 445 | rc = inode_doinit_with_dentry(root_inode, root); |
| @@ -460,15 +493,18 @@ static int selinux_get_mnt_opts(const struct super_block *sb, | |||
| 460 | if (!ss_initialized) | 493 | if (!ss_initialized) |
| 461 | return -EINVAL; | 494 | return -EINVAL; |
| 462 | 495 | ||
| 496 | /* make sure we always check enough bits to cover the mask */ | ||
| 497 | BUILD_BUG_ON(SE_MNTMASK >= (1 << NUM_SEL_MNT_OPTS)); | ||
| 498 | |||
| 463 | tmp = sbsec->flags & SE_MNTMASK; | 499 | tmp = sbsec->flags & SE_MNTMASK; |
| 464 | /* count the number of mount options for this sb */ | 500 | /* count the number of mount options for this sb */ |
| 465 | for (i = 0; i < 8; i++) { | 501 | for (i = 0; i < NUM_SEL_MNT_OPTS; i++) { |
| 466 | if (tmp & 0x01) | 502 | if (tmp & 0x01) |
| 467 | opts->num_mnt_opts++; | 503 | opts->num_mnt_opts++; |
| 468 | tmp >>= 1; | 504 | tmp >>= 1; |
| 469 | } | 505 | } |
| 470 | /* Check if the Label support flag is set */ | 506 | /* Check if the Label support flag is set */ |
| 471 | if (sbsec->flags & SE_SBLABELSUPP) | 507 | if (sbsec->flags & SBLABEL_MNT) |
| 472 | opts->num_mnt_opts++; | 508 | opts->num_mnt_opts++; |
| 473 | 509 | ||
| 474 | opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC); | 510 | opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC); |
| @@ -515,9 +551,9 @@ static int selinux_get_mnt_opts(const struct super_block *sb, | |||
| 515 | opts->mnt_opts[i] = context; | 551 | opts->mnt_opts[i] = context; |
| 516 | opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT; | 552 | opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT; |
| 517 | } | 553 | } |
| 518 | if (sbsec->flags & SE_SBLABELSUPP) { | 554 | if (sbsec->flags & SBLABEL_MNT) { |
| 519 | opts->mnt_opts[i] = NULL; | 555 | opts->mnt_opts[i] = NULL; |
| 520 | opts->mnt_opts_flags[i++] = SE_SBLABELSUPP; | 556 | opts->mnt_opts_flags[i++] = SBLABEL_MNT; |
| 521 | } | 557 | } |
| 522 | 558 | ||
| 523 | BUG_ON(i != opts->num_mnt_opts); | 559 | BUG_ON(i != opts->num_mnt_opts); |
| @@ -614,7 +650,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, | |||
| 614 | for (i = 0; i < num_opts; i++) { | 650 | for (i = 0; i < num_opts; i++) { |
| 615 | u32 sid; | 651 | u32 sid; |
| 616 | 652 | ||
| 617 | if (flags[i] == SE_SBLABELSUPP) | 653 | if (flags[i] == SBLABEL_MNT) |
| 618 | continue; | 654 | continue; |
| 619 | rc = security_context_to_sid(mount_options[i], | 655 | rc = security_context_to_sid(mount_options[i], |
| 620 | strlen(mount_options[i]), &sid); | 656 | strlen(mount_options[i]), &sid); |
| @@ -685,9 +721,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, | |||
| 685 | * Determine the labeling behavior to use for this | 721 | * Determine the labeling behavior to use for this |
| 686 | * filesystem type. | 722 | * filesystem type. |
| 687 | */ | 723 | */ |
| 688 | rc = security_fs_use((sbsec->flags & SE_SBPROC) ? | 724 | rc = security_fs_use(sb); |
| 689 | "proc" : sb->s_type->name, | ||
| 690 | &sbsec->behavior, &sbsec->sid); | ||
| 691 | if (rc) { | 725 | if (rc) { |
| 692 | printk(KERN_WARNING | 726 | printk(KERN_WARNING |
| 693 | "%s: security_fs_use(%s) returned %d\n", | 727 | "%s: security_fs_use(%s) returned %d\n", |
| @@ -1037,7 +1071,7 @@ static void selinux_write_opts(struct seq_file *m, | |||
| 1037 | case DEFCONTEXT_MNT: | 1071 | case DEFCONTEXT_MNT: |
| 1038 | prefix = DEFCONTEXT_STR; | 1072 | prefix = DEFCONTEXT_STR; |
| 1039 | break; | 1073 | break; |
| 1040 | case SE_SBLABELSUPP: | 1074 | case SBLABEL_MNT: |
| 1041 | seq_putc(m, ','); | 1075 | seq_putc(m, ','); |
| 1042 | seq_puts(m, LABELSUPP_STR); | 1076 | seq_puts(m, LABELSUPP_STR); |
| 1043 | continue; | 1077 | continue; |
| @@ -1649,7 +1683,7 @@ static int may_create(struct inode *dir, | |||
| 1649 | if (rc) | 1683 | if (rc) |
| 1650 | return rc; | 1684 | return rc; |
| 1651 | 1685 | ||
| 1652 | if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { | 1686 | if (!newsid || !(sbsec->flags & SBLABEL_MNT)) { |
| 1653 | rc = security_transition_sid(sid, dsec->sid, tclass, | 1687 | rc = security_transition_sid(sid, dsec->sid, tclass, |
| 1654 | &dentry->d_name, &newsid); | 1688 | &dentry->d_name, &newsid); |
| 1655 | if (rc) | 1689 | if (rc) |
| @@ -2437,7 +2471,7 @@ static int selinux_sb_remount(struct super_block *sb, void *data) | |||
| 2437 | u32 sid; | 2471 | u32 sid; |
| 2438 | size_t len; | 2472 | size_t len; |
| 2439 | 2473 | ||
| 2440 | if (flags[i] == SE_SBLABELSUPP) | 2474 | if (flags[i] == SBLABEL_MNT) |
| 2441 | continue; | 2475 | continue; |
| 2442 | len = strlen(mount_options[i]); | 2476 | len = strlen(mount_options[i]); |
| 2443 | rc = security_context_to_sid(mount_options[i], len, &sid); | 2477 | rc = security_context_to_sid(mount_options[i], len, &sid); |
| @@ -2606,7 +2640,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
| 2606 | if ((sbsec->flags & SE_SBINITIALIZED) && | 2640 | if ((sbsec->flags & SE_SBINITIALIZED) && |
| 2607 | (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) | 2641 | (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) |
| 2608 | newsid = sbsec->mntpoint_sid; | 2642 | newsid = sbsec->mntpoint_sid; |
| 2609 | else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { | 2643 | else if (!newsid || !(sbsec->flags & SBLABEL_MNT)) { |
| 2610 | rc = security_transition_sid(sid, dsec->sid, | 2644 | rc = security_transition_sid(sid, dsec->sid, |
| 2611 | inode_mode_to_security_class(inode->i_mode), | 2645 | inode_mode_to_security_class(inode->i_mode), |
| 2612 | qstr, &newsid); | 2646 | qstr, &newsid); |
| @@ -2628,7 +2662,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
| 2628 | isec->initialized = 1; | 2662 | isec->initialized = 1; |
| 2629 | } | 2663 | } |
| 2630 | 2664 | ||
| 2631 | if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP)) | 2665 | if (!ss_initialized || !(sbsec->flags & SBLABEL_MNT)) |
| 2632 | return -EOPNOTSUPP; | 2666 | return -EOPNOTSUPP; |
| 2633 | 2667 | ||
| 2634 | if (name) | 2668 | if (name) |
| @@ -2830,7 +2864,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
| 2830 | return selinux_inode_setotherxattr(dentry, name); | 2864 | return selinux_inode_setotherxattr(dentry, name); |
| 2831 | 2865 | ||
| 2832 | sbsec = inode->i_sb->s_security; | 2866 | sbsec = inode->i_sb->s_security; |
| 2833 | if (!(sbsec->flags & SE_SBLABELSUPP)) | 2867 | if (!(sbsec->flags & SBLABEL_MNT)) |
| 2834 | return -EOPNOTSUPP; | 2868 | return -EOPNOTSUPP; |
| 2835 | 2869 | ||
| 2836 | if (!inode_owner_or_capable(inode)) | 2870 | if (!inode_owner_or_capable(inode)) |
| @@ -3791,8 +3825,12 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid) | |||
| 3791 | u32 nlbl_sid; | 3825 | u32 nlbl_sid; |
| 3792 | u32 nlbl_type; | 3826 | u32 nlbl_type; |
| 3793 | 3827 | ||
| 3794 | selinux_skb_xfrm_sid(skb, &xfrm_sid); | 3828 | err = selinux_xfrm_skb_sid(skb, &xfrm_sid); |
| 3795 | selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid); | 3829 | if (unlikely(err)) |
| 3830 | return -EACCES; | ||
| 3831 | err = selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid); | ||
| 3832 | if (unlikely(err)) | ||
| 3833 | return -EACCES; | ||
| 3796 | 3834 | ||
| 3797 | err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid); | 3835 | err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid); |
| 3798 | if (unlikely(err)) { | 3836 | if (unlikely(err)) { |
| @@ -3805,6 +3843,30 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid) | |||
| 3805 | return 0; | 3843 | return 0; |
| 3806 | } | 3844 | } |
| 3807 | 3845 | ||
| 3846 | /** | ||
| 3847 | * selinux_conn_sid - Determine the child socket label for a connection | ||
| 3848 | * @sk_sid: the parent socket's SID | ||
| 3849 | * @skb_sid: the packet's SID | ||
| 3850 | * @conn_sid: the resulting connection SID | ||
| 3851 | * | ||
| 3852 | * If @skb_sid is valid then the user:role:type information from @sk_sid is | ||
| 3853 | * combined with the MLS information from @skb_sid in order to create | ||
| 3854 | * @conn_sid. If @skb_sid is not valid then then @conn_sid is simply a copy | ||
| 3855 | * of @sk_sid. Returns zero on success, negative values on failure. | ||
| 3856 | * | ||
| 3857 | */ | ||
| 3858 | static int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid) | ||
| 3859 | { | ||
| 3860 | int err = 0; | ||
| 3861 | |||
| 3862 | if (skb_sid != SECSID_NULL) | ||
| 3863 | err = security_sid_mls_copy(sk_sid, skb_sid, conn_sid); | ||
| 3864 | else | ||
| 3865 | *conn_sid = sk_sid; | ||
| 3866 | |||
| 3867 | return err; | ||
| 3868 | } | ||
| 3869 | |||
| 3808 | /* socket security operations */ | 3870 | /* socket security operations */ |
| 3809 | 3871 | ||
| 3810 | static int socket_sockcreate_sid(const struct task_security_struct *tsec, | 3872 | static int socket_sockcreate_sid(const struct task_security_struct *tsec, |
| @@ -4246,7 +4308,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
| 4246 | return selinux_sock_rcv_skb_compat(sk, skb, family); | 4308 | return selinux_sock_rcv_skb_compat(sk, skb, family); |
| 4247 | 4309 | ||
| 4248 | secmark_active = selinux_secmark_enabled(); | 4310 | secmark_active = selinux_secmark_enabled(); |
| 4249 | peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); | 4311 | peerlbl_active = selinux_peerlbl_enabled(); |
| 4250 | if (!secmark_active && !peerlbl_active) | 4312 | if (!secmark_active && !peerlbl_active) |
| 4251 | return 0; | 4313 | return 0; |
| 4252 | 4314 | ||
| @@ -4411,7 +4473,7 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
| 4411 | struct sk_security_struct *sksec = sk->sk_security; | 4473 | struct sk_security_struct *sksec = sk->sk_security; |
| 4412 | int err; | 4474 | int err; |
| 4413 | u16 family = sk->sk_family; | 4475 | u16 family = sk->sk_family; |
| 4414 | u32 newsid; | 4476 | u32 connsid; |
| 4415 | u32 peersid; | 4477 | u32 peersid; |
| 4416 | 4478 | ||
| 4417 | /* handle mapped IPv4 packets arriving via IPv6 sockets */ | 4479 | /* handle mapped IPv4 packets arriving via IPv6 sockets */ |
| @@ -4421,16 +4483,11 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
| 4421 | err = selinux_skb_peerlbl_sid(skb, family, &peersid); | 4483 | err = selinux_skb_peerlbl_sid(skb, family, &peersid); |
| 4422 | if (err) | 4484 | if (err) |
| 4423 | return err; | 4485 | return err; |
| 4424 | if (peersid == SECSID_NULL) { | 4486 | err = selinux_conn_sid(sksec->sid, peersid, &connsid); |
| 4425 | req->secid = sksec->sid; | 4487 | if (err) |
| 4426 | req->peer_secid = SECSID_NULL; | 4488 | return err; |
| 4427 | } else { | 4489 | req->secid = connsid; |
| 4428 | err = security_sid_mls_copy(sksec->sid, peersid, &newsid); | 4490 | req->peer_secid = peersid; |
| 4429 | if (err) | ||
| 4430 | return err; | ||
| 4431 | req->secid = newsid; | ||
| 4432 | req->peer_secid = peersid; | ||
| 4433 | } | ||
| 4434 | 4491 | ||
| 4435 | return selinux_netlbl_inet_conn_request(req, family); | 4492 | return selinux_netlbl_inet_conn_request(req, family); |
| 4436 | } | 4493 | } |
| @@ -4628,7 +4685,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, | |||
| 4628 | 4685 | ||
| 4629 | secmark_active = selinux_secmark_enabled(); | 4686 | secmark_active = selinux_secmark_enabled(); |
| 4630 | netlbl_active = netlbl_enabled(); | 4687 | netlbl_active = netlbl_enabled(); |
| 4631 | peerlbl_active = netlbl_active || selinux_xfrm_enabled(); | 4688 | peerlbl_active = selinux_peerlbl_enabled(); |
| 4632 | if (!secmark_active && !peerlbl_active) | 4689 | if (!secmark_active && !peerlbl_active) |
| 4633 | return NF_ACCEPT; | 4690 | return NF_ACCEPT; |
| 4634 | 4691 | ||
| @@ -4690,6 +4747,7 @@ static unsigned int selinux_ipv6_forward(const struct nf_hook_ops *ops, | |||
| 4690 | static unsigned int selinux_ip_output(struct sk_buff *skb, | 4747 | static unsigned int selinux_ip_output(struct sk_buff *skb, |
| 4691 | u16 family) | 4748 | u16 family) |
| 4692 | { | 4749 | { |
| 4750 | struct sock *sk; | ||
| 4693 | u32 sid; | 4751 | u32 sid; |
| 4694 | 4752 | ||
| 4695 | if (!netlbl_enabled()) | 4753 | if (!netlbl_enabled()) |
| @@ -4698,8 +4756,27 @@ static unsigned int selinux_ip_output(struct sk_buff *skb, | |||
| 4698 | /* we do this in the LOCAL_OUT path and not the POST_ROUTING path | 4756 | /* we do this in the LOCAL_OUT path and not the POST_ROUTING path |
| 4699 | * because we want to make sure we apply the necessary labeling | 4757 | * because we want to make sure we apply the necessary labeling |
| 4700 | * before IPsec is applied so we can leverage AH protection */ | 4758 | * before IPsec is applied so we can leverage AH protection */ |
| 4701 | if (skb->sk) { | 4759 | sk = skb->sk; |
| 4702 | struct sk_security_struct *sksec = skb->sk->sk_security; | 4760 | if (sk) { |
| 4761 | struct sk_security_struct *sksec; | ||
| 4762 | |||
| 4763 | if (sk->sk_state == TCP_LISTEN) | ||
| 4764 | /* if the socket is the listening state then this | ||
| 4765 | * packet is a SYN-ACK packet which means it needs to | ||
| 4766 | * be labeled based on the connection/request_sock and | ||
| 4767 | * not the parent socket. unfortunately, we can't | ||
| 4768 | * lookup the request_sock yet as it isn't queued on | ||
| 4769 | * the parent socket until after the SYN-ACK is sent. | ||
| 4770 | * the "solution" is to simply pass the packet as-is | ||
| 4771 | * as any IP option based labeling should be copied | ||
| 4772 | * from the initial connection request (in the IP | ||
| 4773 | * layer). it is far from ideal, but until we get a | ||
| 4774 | * security label in the packet itself this is the | ||
| 4775 | * best we can do. */ | ||
| 4776 | return NF_ACCEPT; | ||
| 4777 | |||
| 4778 | /* standard practice, label using the parent socket */ | ||
| 4779 | sksec = sk->sk_security; | ||
| 4703 | sid = sksec->sid; | 4780 | sid = sksec->sid; |
| 4704 | } else | 4781 | } else |
| 4705 | sid = SECINITSID_KERNEL; | 4782 | sid = SECINITSID_KERNEL; |
| @@ -4769,27 +4846,36 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
| 4769 | * as fast and as clean as possible. */ | 4846 | * as fast and as clean as possible. */ |
| 4770 | if (!selinux_policycap_netpeer) | 4847 | if (!selinux_policycap_netpeer) |
| 4771 | return selinux_ip_postroute_compat(skb, ifindex, family); | 4848 | return selinux_ip_postroute_compat(skb, ifindex, family); |
| 4849 | |||
| 4850 | secmark_active = selinux_secmark_enabled(); | ||
| 4851 | peerlbl_active = selinux_peerlbl_enabled(); | ||
| 4852 | if (!secmark_active && !peerlbl_active) | ||
| 4853 | return NF_ACCEPT; | ||
| 4854 | |||
| 4855 | sk = skb->sk; | ||
| 4856 | |||
| 4772 | #ifdef CONFIG_XFRM | 4857 | #ifdef CONFIG_XFRM |
| 4773 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec | 4858 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec |
| 4774 | * packet transformation so allow the packet to pass without any checks | 4859 | * packet transformation so allow the packet to pass without any checks |
| 4775 | * since we'll have another chance to perform access control checks | 4860 | * since we'll have another chance to perform access control checks |
| 4776 | * when the packet is on it's final way out. | 4861 | * when the packet is on it's final way out. |
| 4777 | * NOTE: there appear to be some IPv6 multicast cases where skb->dst | 4862 | * NOTE: there appear to be some IPv6 multicast cases where skb->dst |
| 4778 | * is NULL, in this case go ahead and apply access control. */ | 4863 | * is NULL, in this case go ahead and apply access control. |
| 4779 | if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL) | 4864 | * NOTE: if this is a local socket (skb->sk != NULL) that is in the |
| 4865 | * TCP listening state we cannot wait until the XFRM processing | ||
| 4866 | * is done as we will miss out on the SA label if we do; | ||
| 4867 | * unfortunately, this means more work, but it is only once per | ||
| 4868 | * connection. */ | ||
| 4869 | if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL && | ||
| 4870 | !(sk != NULL && sk->sk_state == TCP_LISTEN)) | ||
| 4780 | return NF_ACCEPT; | 4871 | return NF_ACCEPT; |
| 4781 | #endif | 4872 | #endif |
| 4782 | secmark_active = selinux_secmark_enabled(); | ||
| 4783 | peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); | ||
| 4784 | if (!secmark_active && !peerlbl_active) | ||
| 4785 | return NF_ACCEPT; | ||
| 4786 | 4873 | ||
| 4787 | /* if the packet is being forwarded then get the peer label from the | ||
| 4788 | * packet itself; otherwise check to see if it is from a local | ||
| 4789 | * application or the kernel, if from an application get the peer label | ||
| 4790 | * from the sending socket, otherwise use the kernel's sid */ | ||
| 4791 | sk = skb->sk; | ||
| 4792 | if (sk == NULL) { | 4874 | if (sk == NULL) { |
| 4875 | /* Without an associated socket the packet is either coming | ||
| 4876 | * from the kernel or it is being forwarded; check the packet | ||
| 4877 | * to determine which and if the packet is being forwarded | ||
| 4878 | * query the packet directly to determine the security label. */ | ||
| 4793 | if (skb->skb_iif) { | 4879 | if (skb->skb_iif) { |
| 4794 | secmark_perm = PACKET__FORWARD_OUT; | 4880 | secmark_perm = PACKET__FORWARD_OUT; |
| 4795 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) | 4881 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) |
| @@ -4798,7 +4884,45 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
| 4798 | secmark_perm = PACKET__SEND; | 4884 | secmark_perm = PACKET__SEND; |
| 4799 | peer_sid = SECINITSID_KERNEL; | 4885 | peer_sid = SECINITSID_KERNEL; |
| 4800 | } | 4886 | } |
| 4887 | } else if (sk->sk_state == TCP_LISTEN) { | ||
| 4888 | /* Locally generated packet but the associated socket is in the | ||
| 4889 | * listening state which means this is a SYN-ACK packet. In | ||
| 4890 | * this particular case the correct security label is assigned | ||
| 4891 | * to the connection/request_sock but unfortunately we can't | ||
| 4892 | * query the request_sock as it isn't queued on the parent | ||
| 4893 | * socket until after the SYN-ACK packet is sent; the only | ||
| 4894 | * viable choice is to regenerate the label like we do in | ||
| 4895 | * selinux_inet_conn_request(). See also selinux_ip_output() | ||
| 4896 | * for similar problems. */ | ||
| 4897 | u32 skb_sid; | ||
| 4898 | struct sk_security_struct *sksec = sk->sk_security; | ||
| 4899 | if (selinux_skb_peerlbl_sid(skb, family, &skb_sid)) | ||
| 4900 | return NF_DROP; | ||
| 4901 | /* At this point, if the returned skb peerlbl is SECSID_NULL | ||
| 4902 | * and the packet has been through at least one XFRM | ||
| 4903 | * transformation then we must be dealing with the "final" | ||
| 4904 | * form of labeled IPsec packet; since we've already applied | ||
| 4905 | * all of our access controls on this packet we can safely | ||
| 4906 | * pass the packet. */ | ||
| 4907 | if (skb_sid == SECSID_NULL) { | ||
| 4908 | switch (family) { | ||
| 4909 | case PF_INET: | ||
| 4910 | if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) | ||
| 4911 | return NF_ACCEPT; | ||
| 4912 | break; | ||
| 4913 | case PF_INET6: | ||
| 4914 | if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) | ||
| 4915 | return NF_ACCEPT; | ||
| 4916 | default: | ||
| 4917 | return NF_DROP_ERR(-ECONNREFUSED); | ||
| 4918 | } | ||
| 4919 | } | ||
| 4920 | if (selinux_conn_sid(sksec->sid, skb_sid, &peer_sid)) | ||
| 4921 | return NF_DROP; | ||
| 4922 | secmark_perm = PACKET__SEND; | ||
| 4801 | } else { | 4923 | } else { |
| 4924 | /* Locally generated packet, fetch the security label from the | ||
| 4925 | * associated socket. */ | ||
| 4802 | struct sk_security_struct *sksec = sk->sk_security; | 4926 | struct sk_security_struct *sksec = sk->sk_security; |
| 4803 | peer_sid = sksec->sid; | 4927 | peer_sid = sksec->sid; |
| 4804 | secmark_perm = PACKET__SEND; | 4928 | secmark_perm = PACKET__SEND; |
| @@ -5784,7 +5908,8 @@ static struct security_operations selinux_ops = { | |||
| 5784 | .xfrm_policy_clone_security = selinux_xfrm_policy_clone, | 5908 | .xfrm_policy_clone_security = selinux_xfrm_policy_clone, |
| 5785 | .xfrm_policy_free_security = selinux_xfrm_policy_free, | 5909 | .xfrm_policy_free_security = selinux_xfrm_policy_free, |
| 5786 | .xfrm_policy_delete_security = selinux_xfrm_policy_delete, | 5910 | .xfrm_policy_delete_security = selinux_xfrm_policy_delete, |
| 5787 | .xfrm_state_alloc_security = selinux_xfrm_state_alloc, | 5911 | .xfrm_state_alloc = selinux_xfrm_state_alloc, |
| 5912 | .xfrm_state_alloc_acquire = selinux_xfrm_state_alloc_acquire, | ||
| 5788 | .xfrm_state_free_security = selinux_xfrm_state_free, | 5913 | .xfrm_state_free_security = selinux_xfrm_state_free, |
| 5789 | .xfrm_state_delete_security = selinux_xfrm_state_delete, | 5914 | .xfrm_state_delete_security = selinux_xfrm_state_delete, |
| 5790 | .xfrm_policy_lookup = selinux_xfrm_policy_lookup, | 5915 | .xfrm_policy_lookup = selinux_xfrm_policy_lookup, |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index aa47bcabb5f6..b1dfe1049450 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
| @@ -58,8 +58,8 @@ struct superblock_security_struct { | |||
| 58 | u32 sid; /* SID of file system superblock */ | 58 | u32 sid; /* SID of file system superblock */ |
| 59 | u32 def_sid; /* default SID for labeling */ | 59 | u32 def_sid; /* default SID for labeling */ |
| 60 | u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */ | 60 | u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */ |
| 61 | unsigned int behavior; /* labeling behavior */ | 61 | unsigned short behavior; /* labeling behavior */ |
| 62 | unsigned char flags; /* which mount options were specified */ | 62 | unsigned short flags; /* which mount options were specified */ |
| 63 | struct mutex lock; | 63 | struct mutex lock; |
| 64 | struct list_head isec_head; | 64 | struct list_head isec_head; |
| 65 | spinlock_t isec_lock; | 65 | spinlock_t isec_lock; |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 8fd8e18ea340..fe341ae37004 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
| @@ -45,14 +45,15 @@ | |||
| 45 | /* Mask for just the mount related flags */ | 45 | /* Mask for just the mount related flags */ |
| 46 | #define SE_MNTMASK 0x0f | 46 | #define SE_MNTMASK 0x0f |
| 47 | /* Super block security struct flags for mount options */ | 47 | /* Super block security struct flags for mount options */ |
| 48 | /* BE CAREFUL, these need to be the low order bits for selinux_get_mnt_opts */ | ||
| 48 | #define CONTEXT_MNT 0x01 | 49 | #define CONTEXT_MNT 0x01 |
| 49 | #define FSCONTEXT_MNT 0x02 | 50 | #define FSCONTEXT_MNT 0x02 |
| 50 | #define ROOTCONTEXT_MNT 0x04 | 51 | #define ROOTCONTEXT_MNT 0x04 |
| 51 | #define DEFCONTEXT_MNT 0x08 | 52 | #define DEFCONTEXT_MNT 0x08 |
| 53 | #define SBLABEL_MNT 0x10 | ||
| 52 | /* Non-mount related flags */ | 54 | /* Non-mount related flags */ |
| 53 | #define SE_SBINITIALIZED 0x10 | 55 | #define SE_SBINITIALIZED 0x0100 |
| 54 | #define SE_SBPROC 0x20 | 56 | #define SE_SBPROC 0x0200 |
| 55 | #define SE_SBLABELSUPP 0x40 | ||
| 56 | 57 | ||
| 57 | #define CONTEXT_STR "context=" | 58 | #define CONTEXT_STR "context=" |
| 58 | #define FSCONTEXT_STR "fscontext=" | 59 | #define FSCONTEXT_STR "fscontext=" |
| @@ -68,12 +69,15 @@ extern int selinux_enabled; | |||
| 68 | enum { | 69 | enum { |
| 69 | POLICYDB_CAPABILITY_NETPEER, | 70 | POLICYDB_CAPABILITY_NETPEER, |
| 70 | POLICYDB_CAPABILITY_OPENPERM, | 71 | POLICYDB_CAPABILITY_OPENPERM, |
| 72 | POLICYDB_CAPABILITY_REDHAT1, | ||
| 73 | POLICYDB_CAPABILITY_ALWAYSNETWORK, | ||
| 71 | __POLICYDB_CAPABILITY_MAX | 74 | __POLICYDB_CAPABILITY_MAX |
| 72 | }; | 75 | }; |
| 73 | #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1) | 76 | #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1) |
| 74 | 77 | ||
| 75 | extern int selinux_policycap_netpeer; | 78 | extern int selinux_policycap_netpeer; |
| 76 | extern int selinux_policycap_openperm; | 79 | extern int selinux_policycap_openperm; |
| 80 | extern int selinux_policycap_alwaysnetwork; | ||
| 77 | 81 | ||
| 78 | /* | 82 | /* |
| 79 | * type_datum properties | 83 | * type_datum properties |
| @@ -172,8 +176,7 @@ int security_get_allow_unknown(void); | |||
| 172 | #define SECURITY_FS_USE_NATIVE 7 /* use native label support */ | 176 | #define SECURITY_FS_USE_NATIVE 7 /* use native label support */ |
| 173 | #define SECURITY_FS_USE_MAX 7 /* Highest SECURITY_FS_USE_XXX */ | 177 | #define SECURITY_FS_USE_MAX 7 /* Highest SECURITY_FS_USE_XXX */ |
| 174 | 178 | ||
| 175 | int security_fs_use(const char *fstype, unsigned int *behavior, | 179 | int security_fs_use(struct super_block *sb); |
| 176 | u32 *sid); | ||
| 177 | 180 | ||
| 178 | int security_genfs_sid(const char *fstype, char *name, u16 sclass, | 181 | int security_genfs_sid(const char *fstype, char *name, u16 sclass, |
| 179 | u32 *sid); | 182 | u32 *sid); |
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 6713f04e30ba..48c3cc94c168 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h | |||
| @@ -10,29 +10,21 @@ | |||
| 10 | #include <net/flow.h> | 10 | #include <net/flow.h> |
| 11 | 11 | ||
| 12 | int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, | 12 | int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, |
| 13 | struct xfrm_user_sec_ctx *sec_ctx); | 13 | struct xfrm_user_sec_ctx *uctx); |
| 14 | int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, | 14 | int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, |
| 15 | struct xfrm_sec_ctx **new_ctxp); | 15 | struct xfrm_sec_ctx **new_ctxp); |
| 16 | void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx); | 16 | void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx); |
| 17 | int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx); | 17 | int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx); |
| 18 | int selinux_xfrm_state_alloc(struct xfrm_state *x, | 18 | int selinux_xfrm_state_alloc(struct xfrm_state *x, |
| 19 | struct xfrm_user_sec_ctx *sec_ctx, u32 secid); | 19 | struct xfrm_user_sec_ctx *uctx); |
| 20 | int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x, | ||
| 21 | struct xfrm_sec_ctx *polsec, u32 secid); | ||
| 20 | void selinux_xfrm_state_free(struct xfrm_state *x); | 22 | void selinux_xfrm_state_free(struct xfrm_state *x); |
| 21 | int selinux_xfrm_state_delete(struct xfrm_state *x); | 23 | int selinux_xfrm_state_delete(struct xfrm_state *x); |
| 22 | int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir); | 24 | int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir); |
| 23 | int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, | 25 | int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, |
| 24 | struct xfrm_policy *xp, const struct flowi *fl); | 26 | struct xfrm_policy *xp, |
| 25 | 27 | const struct flowi *fl); | |
| 26 | /* | ||
| 27 | * Extract the security blob from the sock (it's actually on the socket) | ||
| 28 | */ | ||
| 29 | static inline struct inode_security_struct *get_sock_isec(struct sock *sk) | ||
| 30 | { | ||
| 31 | if (!sk->sk_socket) | ||
| 32 | return NULL; | ||
| 33 | |||
| 34 | return SOCK_INODE(sk->sk_socket)->i_security; | ||
| 35 | } | ||
| 36 | 28 | ||
| 37 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 29 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
| 38 | extern atomic_t selinux_xfrm_refcount; | 30 | extern atomic_t selinux_xfrm_refcount; |
| @@ -42,11 +34,12 @@ static inline int selinux_xfrm_enabled(void) | |||
| 42 | return (atomic_read(&selinux_xfrm_refcount) > 0); | 34 | return (atomic_read(&selinux_xfrm_refcount) > 0); |
| 43 | } | 35 | } |
| 44 | 36 | ||
| 45 | int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb, | 37 | int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb, |
| 46 | struct common_audit_data *ad); | 38 | struct common_audit_data *ad); |
| 47 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, | 39 | int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb, |
| 48 | struct common_audit_data *ad, u8 proto); | 40 | struct common_audit_data *ad, u8 proto); |
| 49 | int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); | 41 | int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); |
| 42 | int selinux_xfrm_skb_sid(struct sk_buff *skb, u32 *sid); | ||
| 50 | 43 | ||
| 51 | static inline void selinux_xfrm_notify_policyload(void) | 44 | static inline void selinux_xfrm_notify_policyload(void) |
| 52 | { | 45 | { |
| @@ -64,19 +57,21 @@ static inline int selinux_xfrm_enabled(void) | |||
| 64 | return 0; | 57 | return 0; |
| 65 | } | 58 | } |
| 66 | 59 | ||
| 67 | static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, | 60 | static inline int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb, |
| 68 | struct common_audit_data *ad) | 61 | struct common_audit_data *ad) |
| 69 | { | 62 | { |
| 70 | return 0; | 63 | return 0; |
| 71 | } | 64 | } |
| 72 | 65 | ||
| 73 | static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, | 66 | static inline int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb, |
| 74 | struct common_audit_data *ad, u8 proto) | 67 | struct common_audit_data *ad, |
| 68 | u8 proto) | ||
| 75 | { | 69 | { |
| 76 | return 0; | 70 | return 0; |
| 77 | } | 71 | } |
| 78 | 72 | ||
| 79 | static inline int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) | 73 | static inline int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, |
| 74 | int ckall) | ||
| 80 | { | 75 | { |
| 81 | *sid = SECSID_NULL; | 76 | *sid = SECSID_NULL; |
| 82 | return 0; | 77 | return 0; |
| @@ -85,12 +80,12 @@ static inline int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int | |||
| 85 | static inline void selinux_xfrm_notify_policyload(void) | 80 | static inline void selinux_xfrm_notify_policyload(void) |
| 86 | { | 81 | { |
| 87 | } | 82 | } |
| 88 | #endif | ||
| 89 | 83 | ||
| 90 | static inline void selinux_skb_xfrm_sid(struct sk_buff *skb, u32 *sid) | 84 | static inline int selinux_xfrm_skb_sid(struct sk_buff *skb, u32 *sid) |
| 91 | { | 85 | { |
| 92 | int err = selinux_xfrm_decode_session(skb, sid, 0); | 86 | *sid = SECSID_NULL; |
| 93 | BUG_ON(err); | 87 | return 0; |
| 94 | } | 88 | } |
| 89 | #endif | ||
| 95 | 90 | ||
| 96 | #endif /* _SELINUX_XFRM_H_ */ | 91 | #endif /* _SELINUX_XFRM_H_ */ |
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index da4b8b233280..6235d052338b 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
| @@ -442,8 +442,7 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) | |||
| 442 | sksec->nlbl_state != NLBL_CONNLABELED) | 442 | sksec->nlbl_state != NLBL_CONNLABELED) |
| 443 | return 0; | 443 | return 0; |
| 444 | 444 | ||
| 445 | local_bh_disable(); | 445 | lock_sock(sk); |
| 446 | bh_lock_sock_nested(sk); | ||
| 447 | 446 | ||
| 448 | /* connected sockets are allowed to disconnect when the address family | 447 | /* connected sockets are allowed to disconnect when the address family |
| 449 | * is set to AF_UNSPEC, if that is what is happening we want to reset | 448 | * is set to AF_UNSPEC, if that is what is happening we want to reset |
| @@ -464,7 +463,6 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) | |||
| 464 | sksec->nlbl_state = NLBL_CONNLABELED; | 463 | sksec->nlbl_state = NLBL_CONNLABELED; |
| 465 | 464 | ||
| 466 | socket_connect_return: | 465 | socket_connect_return: |
| 467 | bh_unlock_sock(sk); | 466 | release_sock(sk); |
| 468 | local_bh_enable(); | ||
| 469 | return rc; | 467 | return rc; |
| 470 | } | 468 | } |
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c index c5454c0477c3..03a72c32afd7 100644 --- a/security/selinux/netnode.c +++ b/security/selinux/netnode.c | |||
| @@ -166,6 +166,7 @@ static void sel_netnode_insert(struct sel_netnode *node) | |||
| 166 | break; | 166 | break; |
| 167 | default: | 167 | default: |
| 168 | BUG(); | 168 | BUG(); |
| 169 | return; | ||
| 169 | } | 170 | } |
| 170 | 171 | ||
| 171 | /* we need to impose a limit on the growth of the hash table so check | 172 | /* we need to impose a limit on the growth of the hash table so check |
| @@ -225,6 +226,7 @@ static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid) | |||
| 225 | break; | 226 | break; |
| 226 | default: | 227 | default: |
| 227 | BUG(); | 228 | BUG(); |
| 229 | ret = -EINVAL; | ||
| 228 | } | 230 | } |
| 229 | if (ret != 0) | 231 | if (ret != 0) |
| 230 | goto out; | 232 | goto out; |
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 855e464e92ef..332ac8a80cf5 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c | |||
| @@ -116,6 +116,8 @@ static struct nlmsg_perm nlmsg_audit_perms[] = | |||
| 116 | { AUDIT_MAKE_EQUIV, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, | 116 | { AUDIT_MAKE_EQUIV, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, |
| 117 | { AUDIT_TTY_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ }, | 117 | { AUDIT_TTY_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ }, |
| 118 | { AUDIT_TTY_SET, NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT }, | 118 | { AUDIT_TTY_SET, NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT }, |
| 119 | { AUDIT_GET_FEATURE, NETLINK_AUDIT_SOCKET__NLMSG_READ }, | ||
| 120 | { AUDIT_SET_FEATURE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, | ||
| 119 | }; | 121 | }; |
| 120 | 122 | ||
| 121 | 123 | ||
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index ff427733c290..5122affe06a8 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
| @@ -44,7 +44,9 @@ | |||
| 44 | /* Policy capability filenames */ | 44 | /* Policy capability filenames */ |
| 45 | static char *policycap_names[] = { | 45 | static char *policycap_names[] = { |
| 46 | "network_peer_controls", | 46 | "network_peer_controls", |
| 47 | "open_perms" | 47 | "open_perms", |
| 48 | "redhat1", | ||
| 49 | "always_check_network" | ||
| 48 | }; | 50 | }; |
| 49 | 51 | ||
| 50 | unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; | 52 | unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; |
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 30f119b1d1ec..820313a04d49 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c | |||
| @@ -213,7 +213,12 @@ netlbl_import_failure: | |||
| 213 | } | 213 | } |
| 214 | #endif /* CONFIG_NETLABEL */ | 214 | #endif /* CONFIG_NETLABEL */ |
| 215 | 215 | ||
| 216 | int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) | 216 | /* |
| 217 | * Check to see if all the bits set in e2 are also set in e1. Optionally, | ||
| 218 | * if last_e2bit is non-zero, the highest set bit in e2 cannot exceed | ||
| 219 | * last_e2bit. | ||
| 220 | */ | ||
| 221 | int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2, u32 last_e2bit) | ||
| 217 | { | 222 | { |
| 218 | struct ebitmap_node *n1, *n2; | 223 | struct ebitmap_node *n1, *n2; |
| 219 | int i; | 224 | int i; |
| @@ -223,14 +228,25 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) | |||
| 223 | 228 | ||
| 224 | n1 = e1->node; | 229 | n1 = e1->node; |
| 225 | n2 = e2->node; | 230 | n2 = e2->node; |
| 231 | |||
| 226 | while (n1 && n2 && (n1->startbit <= n2->startbit)) { | 232 | while (n1 && n2 && (n1->startbit <= n2->startbit)) { |
| 227 | if (n1->startbit < n2->startbit) { | 233 | if (n1->startbit < n2->startbit) { |
| 228 | n1 = n1->next; | 234 | n1 = n1->next; |
| 229 | continue; | 235 | continue; |
| 230 | } | 236 | } |
| 231 | for (i = 0; i < EBITMAP_UNIT_NUMS; i++) { | 237 | for (i = EBITMAP_UNIT_NUMS - 1; (i >= 0) && !n2->maps[i]; ) |
| 238 | i--; /* Skip trailing NULL map entries */ | ||
| 239 | if (last_e2bit && (i >= 0)) { | ||
| 240 | u32 lastsetbit = n2->startbit + i * EBITMAP_UNIT_SIZE + | ||
| 241 | __fls(n2->maps[i]); | ||
| 242 | if (lastsetbit > last_e2bit) | ||
| 243 | return 0; | ||
| 244 | } | ||
| 245 | |||
| 246 | while (i >= 0) { | ||
| 232 | if ((n1->maps[i] & n2->maps[i]) != n2->maps[i]) | 247 | if ((n1->maps[i] & n2->maps[i]) != n2->maps[i]) |
| 233 | return 0; | 248 | return 0; |
| 249 | i--; | ||
| 234 | } | 250 | } |
| 235 | 251 | ||
| 236 | n1 = n1->next; | 252 | n1 = n1->next; |
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h index 922f8afa89dd..712c8a7b8e8b 100644 --- a/security/selinux/ss/ebitmap.h +++ b/security/selinux/ss/ebitmap.h | |||
| @@ -16,7 +16,13 @@ | |||
| 16 | 16 | ||
| 17 | #include <net/netlabel.h> | 17 | #include <net/netlabel.h> |
| 18 | 18 | ||
| 19 | #define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) \ | 19 | #ifdef CONFIG_64BIT |
| 20 | #define EBITMAP_NODE_SIZE 64 | ||
| 21 | #else | ||
| 22 | #define EBITMAP_NODE_SIZE 32 | ||
| 23 | #endif | ||
| 24 | |||
| 25 | #define EBITMAP_UNIT_NUMS ((EBITMAP_NODE_SIZE-sizeof(void *)-sizeof(u32))\ | ||
| 20 | / sizeof(unsigned long)) | 26 | / sizeof(unsigned long)) |
| 21 | #define EBITMAP_UNIT_SIZE BITS_PER_LONG | 27 | #define EBITMAP_UNIT_SIZE BITS_PER_LONG |
| 22 | #define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE) | 28 | #define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE) |
| @@ -117,7 +123,7 @@ static inline void ebitmap_node_clr_bit(struct ebitmap_node *n, | |||
| 117 | 123 | ||
| 118 | int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2); | 124 | int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2); |
| 119 | int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src); | 125 | int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src); |
| 120 | int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2); | 126 | int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2, u32 last_e2bit); |
| 121 | int ebitmap_get_bit(struct ebitmap *e, unsigned long bit); | 127 | int ebitmap_get_bit(struct ebitmap *e, unsigned long bit); |
| 122 | int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value); | 128 | int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value); |
| 123 | void ebitmap_destroy(struct ebitmap *e); | 129 | void ebitmap_destroy(struct ebitmap *e); |
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 40de8d3f208e..c85bc1ec040c 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c | |||
| @@ -160,8 +160,6 @@ void mls_sid_to_context(struct context *context, | |||
| 160 | int mls_level_isvalid(struct policydb *p, struct mls_level *l) | 160 | int mls_level_isvalid(struct policydb *p, struct mls_level *l) |
| 161 | { | 161 | { |
| 162 | struct level_datum *levdatum; | 162 | struct level_datum *levdatum; |
| 163 | struct ebitmap_node *node; | ||
| 164 | int i; | ||
| 165 | 163 | ||
| 166 | if (!l->sens || l->sens > p->p_levels.nprim) | 164 | if (!l->sens || l->sens > p->p_levels.nprim) |
| 167 | return 0; | 165 | return 0; |
| @@ -170,19 +168,13 @@ int mls_level_isvalid(struct policydb *p, struct mls_level *l) | |||
| 170 | if (!levdatum) | 168 | if (!levdatum) |
| 171 | return 0; | 169 | return 0; |
| 172 | 170 | ||
| 173 | ebitmap_for_each_positive_bit(&l->cat, node, i) { | 171 | /* |
| 174 | if (i > p->p_cats.nprim) | 172 | * Return 1 iff all the bits set in l->cat are also be set in |
| 175 | return 0; | 173 | * levdatum->level->cat and no bit in l->cat is larger than |
| 176 | if (!ebitmap_get_bit(&levdatum->level->cat, i)) { | 174 | * p->p_cats.nprim. |
| 177 | /* | 175 | */ |
| 178 | * Category may not be associated with | 176 | return ebitmap_contains(&levdatum->level->cat, &l->cat, |
| 179 | * sensitivity. | 177 | p->p_cats.nprim); |
| 180 | */ | ||
| 181 | return 0; | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | return 1; | ||
| 186 | } | 178 | } |
| 187 | 179 | ||
| 188 | int mls_range_isvalid(struct policydb *p, struct mls_range *r) | 180 | int mls_range_isvalid(struct policydb *p, struct mls_range *r) |
diff --git a/security/selinux/ss/mls_types.h b/security/selinux/ss/mls_types.h index 03bed52a8052..e93648774137 100644 --- a/security/selinux/ss/mls_types.h +++ b/security/selinux/ss/mls_types.h | |||
| @@ -35,7 +35,7 @@ static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2) | |||
| 35 | static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2) | 35 | static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2) |
| 36 | { | 36 | { |
| 37 | return ((l1->sens >= l2->sens) && | 37 | return ((l1->sens >= l2->sens) && |
| 38 | ebitmap_contains(&l1->cat, &l2->cat)); | 38 | ebitmap_contains(&l1->cat, &l2->cat, 0)); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | #define mls_level_incomp(l1, l2) \ | 41 | #define mls_level_incomp(l1, l2) \ |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index c8adde3aff8f..f6195ebde3c9 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
| @@ -3203,9 +3203,8 @@ static int range_write_helper(void *key, void *data, void *ptr) | |||
| 3203 | 3203 | ||
| 3204 | static int range_write(struct policydb *p, void *fp) | 3204 | static int range_write(struct policydb *p, void *fp) |
| 3205 | { | 3205 | { |
| 3206 | size_t nel; | ||
| 3207 | __le32 buf[1]; | 3206 | __le32 buf[1]; |
| 3208 | int rc; | 3207 | int rc, nel; |
| 3209 | struct policy_data pd; | 3208 | struct policy_data pd; |
| 3210 | 3209 | ||
| 3211 | pd.p = p; | 3210 | pd.p = p; |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index b4feecc3fe01..d106733ad987 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
| @@ -72,6 +72,7 @@ | |||
| 72 | 72 | ||
| 73 | int selinux_policycap_netpeer; | 73 | int selinux_policycap_netpeer; |
| 74 | int selinux_policycap_openperm; | 74 | int selinux_policycap_openperm; |
| 75 | int selinux_policycap_alwaysnetwork; | ||
| 75 | 76 | ||
| 76 | static DEFINE_RWLOCK(policy_rwlock); | 77 | static DEFINE_RWLOCK(policy_rwlock); |
| 77 | 78 | ||
| @@ -1812,6 +1813,8 @@ static void security_load_policycaps(void) | |||
| 1812 | POLICYDB_CAPABILITY_NETPEER); | 1813 | POLICYDB_CAPABILITY_NETPEER); |
| 1813 | selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps, | 1814 | selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps, |
| 1814 | POLICYDB_CAPABILITY_OPENPERM); | 1815 | POLICYDB_CAPABILITY_OPENPERM); |
| 1816 | selinux_policycap_alwaysnetwork = ebitmap_get_bit(&policydb.policycaps, | ||
| 1817 | POLICYDB_CAPABILITY_ALWAYSNETWORK); | ||
| 1815 | } | 1818 | } |
| 1816 | 1819 | ||
| 1817 | static int security_preserve_bools(struct policydb *p); | 1820 | static int security_preserve_bools(struct policydb *p); |
| @@ -2323,17 +2326,14 @@ out: | |||
| 2323 | 2326 | ||
| 2324 | /** | 2327 | /** |
| 2325 | * security_fs_use - Determine how to handle labeling for a filesystem. | 2328 | * security_fs_use - Determine how to handle labeling for a filesystem. |
| 2326 | * @fstype: filesystem type | 2329 | * @sb: superblock in question |
| 2327 | * @behavior: labeling behavior | ||
| 2328 | * @sid: SID for filesystem (superblock) | ||
| 2329 | */ | 2330 | */ |
| 2330 | int security_fs_use( | 2331 | int security_fs_use(struct super_block *sb) |
| 2331 | const char *fstype, | ||
| 2332 | unsigned int *behavior, | ||
| 2333 | u32 *sid) | ||
| 2334 | { | 2332 | { |
| 2335 | int rc = 0; | 2333 | int rc = 0; |
| 2336 | struct ocontext *c; | 2334 | struct ocontext *c; |
| 2335 | struct superblock_security_struct *sbsec = sb->s_security; | ||
| 2336 | const char *fstype = sb->s_type->name; | ||
| 2337 | 2337 | ||
| 2338 | read_lock(&policy_rwlock); | 2338 | read_lock(&policy_rwlock); |
| 2339 | 2339 | ||
| @@ -2345,21 +2345,21 @@ int security_fs_use( | |||
| 2345 | } | 2345 | } |
| 2346 | 2346 | ||
| 2347 | if (c) { | 2347 | if (c) { |
| 2348 | *behavior = c->v.behavior; | 2348 | sbsec->behavior = c->v.behavior; |
| 2349 | if (!c->sid[0]) { | 2349 | if (!c->sid[0]) { |
| 2350 | rc = sidtab_context_to_sid(&sidtab, &c->context[0], | 2350 | rc = sidtab_context_to_sid(&sidtab, &c->context[0], |
| 2351 | &c->sid[0]); | 2351 | &c->sid[0]); |
| 2352 | if (rc) | 2352 | if (rc) |
| 2353 | goto out; | 2353 | goto out; |
| 2354 | } | 2354 | } |
| 2355 | *sid = c->sid[0]; | 2355 | sbsec->sid = c->sid[0]; |
| 2356 | } else { | 2356 | } else { |
| 2357 | rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid); | 2357 | rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, &sbsec->sid); |
| 2358 | if (rc) { | 2358 | if (rc) { |
| 2359 | *behavior = SECURITY_FS_USE_NONE; | 2359 | sbsec->behavior = SECURITY_FS_USE_NONE; |
| 2360 | rc = 0; | 2360 | rc = 0; |
| 2361 | } else { | 2361 | } else { |
| 2362 | *behavior = SECURITY_FS_USE_GENFS; | 2362 | sbsec->behavior = SECURITY_FS_USE_GENFS; |
| 2363 | } | 2363 | } |
| 2364 | } | 2364 | } |
| 2365 | 2365 | ||
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index d03081886214..0462cb3ff0a7 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c | |||
| @@ -56,7 +56,7 @@ | |||
| 56 | atomic_t selinux_xfrm_refcount = ATOMIC_INIT(0); | 56 | atomic_t selinux_xfrm_refcount = ATOMIC_INIT(0); |
| 57 | 57 | ||
| 58 | /* | 58 | /* |
| 59 | * Returns true if an LSM/SELinux context | 59 | * Returns true if the context is an LSM/SELinux context. |
| 60 | */ | 60 | */ |
| 61 | static inline int selinux_authorizable_ctx(struct xfrm_sec_ctx *ctx) | 61 | static inline int selinux_authorizable_ctx(struct xfrm_sec_ctx *ctx) |
| 62 | { | 62 | { |
| @@ -66,7 +66,7 @@ static inline int selinux_authorizable_ctx(struct xfrm_sec_ctx *ctx) | |||
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | /* | 68 | /* |
| 69 | * Returns true if the xfrm contains a security blob for SELinux | 69 | * Returns true if the xfrm contains a security blob for SELinux. |
| 70 | */ | 70 | */ |
| 71 | static inline int selinux_authorizable_xfrm(struct xfrm_state *x) | 71 | static inline int selinux_authorizable_xfrm(struct xfrm_state *x) |
| 72 | { | 72 | { |
| @@ -74,48 +74,111 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x) | |||
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | /* | 76 | /* |
| 77 | * LSM hook implementation that authorizes that a flow can use | 77 | * Allocates a xfrm_sec_state and populates it using the supplied security |
| 78 | * a xfrm policy rule. | 78 | * xfrm_user_sec_ctx context. |
| 79 | */ | 79 | */ |
| 80 | int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir) | 80 | static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp, |
| 81 | struct xfrm_user_sec_ctx *uctx) | ||
| 81 | { | 82 | { |
| 82 | int rc; | 83 | int rc; |
| 83 | u32 sel_sid; | 84 | const struct task_security_struct *tsec = current_security(); |
| 85 | struct xfrm_sec_ctx *ctx = NULL; | ||
| 86 | u32 str_len; | ||
| 84 | 87 | ||
| 85 | /* Context sid is either set to label or ANY_ASSOC */ | 88 | if (ctxp == NULL || uctx == NULL || |
| 86 | if (ctx) { | 89 | uctx->ctx_doi != XFRM_SC_DOI_LSM || |
| 87 | if (!selinux_authorizable_ctx(ctx)) | 90 | uctx->ctx_alg != XFRM_SC_ALG_SELINUX) |
| 88 | return -EINVAL; | 91 | return -EINVAL; |
| 89 | 92 | ||
| 90 | sel_sid = ctx->ctx_sid; | 93 | str_len = uctx->ctx_len; |
| 91 | } else | 94 | if (str_len >= PAGE_SIZE) |
| 92 | /* | 95 | return -ENOMEM; |
| 93 | * All flows should be treated as polmatch'ing an | 96 | |
| 94 | * otherwise applicable "non-labeled" policy. This | 97 | ctx = kmalloc(sizeof(*ctx) + str_len + 1, GFP_KERNEL); |
| 95 | * would prevent inadvertent "leaks". | 98 | if (!ctx) |
| 96 | */ | 99 | return -ENOMEM; |
| 97 | return 0; | ||
| 98 | 100 | ||
| 99 | rc = avc_has_perm(fl_secid, sel_sid, SECCLASS_ASSOCIATION, | 101 | ctx->ctx_doi = XFRM_SC_DOI_LSM; |
| 100 | ASSOCIATION__POLMATCH, | 102 | ctx->ctx_alg = XFRM_SC_ALG_SELINUX; |
| 101 | NULL); | 103 | ctx->ctx_len = str_len; |
| 104 | memcpy(ctx->ctx_str, &uctx[1], str_len); | ||
| 105 | ctx->ctx_str[str_len] = '\0'; | ||
| 106 | rc = security_context_to_sid(ctx->ctx_str, str_len, &ctx->ctx_sid); | ||
| 107 | if (rc) | ||
| 108 | goto err; | ||
| 102 | 109 | ||
| 103 | if (rc == -EACCES) | 110 | rc = avc_has_perm(tsec->sid, ctx->ctx_sid, |
| 104 | return -ESRCH; | 111 | SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, NULL); |
| 112 | if (rc) | ||
| 113 | goto err; | ||
| 105 | 114 | ||
| 115 | *ctxp = ctx; | ||
| 116 | atomic_inc(&selinux_xfrm_refcount); | ||
| 117 | return 0; | ||
| 118 | |||
| 119 | err: | ||
| 120 | kfree(ctx); | ||
| 106 | return rc; | 121 | return rc; |
| 107 | } | 122 | } |
| 108 | 123 | ||
| 109 | /* | 124 | /* |
| 125 | * Free the xfrm_sec_ctx structure. | ||
| 126 | */ | ||
| 127 | static void selinux_xfrm_free(struct xfrm_sec_ctx *ctx) | ||
| 128 | { | ||
| 129 | if (!ctx) | ||
| 130 | return; | ||
| 131 | |||
| 132 | atomic_dec(&selinux_xfrm_refcount); | ||
| 133 | kfree(ctx); | ||
| 134 | } | ||
| 135 | |||
| 136 | /* | ||
| 137 | * Authorize the deletion of a labeled SA or policy rule. | ||
| 138 | */ | ||
| 139 | static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx) | ||
| 140 | { | ||
| 141 | const struct task_security_struct *tsec = current_security(); | ||
| 142 | |||
| 143 | if (!ctx) | ||
| 144 | return 0; | ||
| 145 | |||
| 146 | return avc_has_perm(tsec->sid, ctx->ctx_sid, | ||
| 147 | SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, | ||
| 148 | NULL); | ||
| 149 | } | ||
| 150 | |||
| 151 | /* | ||
| 152 | * LSM hook implementation that authorizes that a flow can use a xfrm policy | ||
| 153 | * rule. | ||
| 154 | */ | ||
| 155 | int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir) | ||
| 156 | { | ||
| 157 | int rc; | ||
| 158 | |||
| 159 | /* All flows should be treated as polmatch'ing an otherwise applicable | ||
| 160 | * "non-labeled" policy. This would prevent inadvertent "leaks". */ | ||
| 161 | if (!ctx) | ||
| 162 | return 0; | ||
| 163 | |||
| 164 | /* Context sid is either set to label or ANY_ASSOC */ | ||
| 165 | if (!selinux_authorizable_ctx(ctx)) | ||
| 166 | return -EINVAL; | ||
| 167 | |||
| 168 | rc = avc_has_perm(fl_secid, ctx->ctx_sid, | ||
| 169 | SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, NULL); | ||
| 170 | return (rc == -EACCES ? -ESRCH : rc); | ||
| 171 | } | ||
| 172 | |||
| 173 | /* | ||
| 110 | * LSM hook implementation that authorizes that a state matches | 174 | * LSM hook implementation that authorizes that a state matches |
| 111 | * the given policy, flow combo. | 175 | * the given policy, flow combo. |
| 112 | */ | 176 | */ |
| 113 | 177 | int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, | |
| 114 | int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, | 178 | struct xfrm_policy *xp, |
| 115 | const struct flowi *fl) | 179 | const struct flowi *fl) |
| 116 | { | 180 | { |
| 117 | u32 state_sid; | 181 | u32 state_sid; |
| 118 | int rc; | ||
| 119 | 182 | ||
| 120 | if (!xp->security) | 183 | if (!xp->security) |
| 121 | if (x->security) | 184 | if (x->security) |
| @@ -138,187 +201,111 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy * | |||
| 138 | if (fl->flowi_secid != state_sid) | 201 | if (fl->flowi_secid != state_sid) |
| 139 | return 0; | 202 | return 0; |
| 140 | 203 | ||
| 141 | rc = avc_has_perm(fl->flowi_secid, state_sid, SECCLASS_ASSOCIATION, | 204 | /* We don't need a separate SA Vs. policy polmatch check since the SA |
| 142 | ASSOCIATION__SENDTO, | 205 | * is now of the same label as the flow and a flow Vs. policy polmatch |
| 143 | NULL)? 0:1; | 206 | * check had already happened in selinux_xfrm_policy_lookup() above. */ |
| 144 | 207 | return (avc_has_perm(fl->flowi_secid, state_sid, | |
| 145 | /* | 208 | SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, |
| 146 | * We don't need a separate SA Vs. policy polmatch check | 209 | NULL) ? 0 : 1); |
| 147 | * since the SA is now of the same label as the flow and | ||
| 148 | * a flow Vs. policy polmatch check had already happened | ||
| 149 | * in selinux_xfrm_policy_lookup() above. | ||
| 150 | */ | ||
| 151 | |||
| 152 | return rc; | ||
| 153 | } | 210 | } |
| 154 | 211 | ||
| 155 | /* | 212 | static u32 selinux_xfrm_skb_sid_egress(struct sk_buff *skb) |
| 156 | * LSM hook implementation that checks and/or returns the xfrm sid for the | ||
| 157 | * incoming packet. | ||
| 158 | */ | ||
| 159 | |||
| 160 | int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) | ||
| 161 | { | 213 | { |
| 162 | struct sec_path *sp; | 214 | struct dst_entry *dst = skb_dst(skb); |
| 215 | struct xfrm_state *x; | ||
| 163 | 216 | ||
| 164 | *sid = SECSID_NULL; | 217 | if (dst == NULL) |
| 218 | return SECSID_NULL; | ||
| 219 | x = dst->xfrm; | ||
| 220 | if (x == NULL || !selinux_authorizable_xfrm(x)) | ||
| 221 | return SECSID_NULL; | ||
| 165 | 222 | ||
| 166 | if (skb == NULL) | 223 | return x->security->ctx_sid; |
| 167 | return 0; | 224 | } |
| 225 | |||
| 226 | static int selinux_xfrm_skb_sid_ingress(struct sk_buff *skb, | ||
| 227 | u32 *sid, int ckall) | ||
| 228 | { | ||
| 229 | u32 sid_session = SECSID_NULL; | ||
| 230 | struct sec_path *sp = skb->sp; | ||
| 168 | 231 | ||
| 169 | sp = skb->sp; | ||
| 170 | if (sp) { | 232 | if (sp) { |
| 171 | int i, sid_set = 0; | 233 | int i; |
| 172 | 234 | ||
| 173 | for (i = sp->len-1; i >= 0; i--) { | 235 | for (i = sp->len - 1; i >= 0; i--) { |
| 174 | struct xfrm_state *x = sp->xvec[i]; | 236 | struct xfrm_state *x = sp->xvec[i]; |
| 175 | if (selinux_authorizable_xfrm(x)) { | 237 | if (selinux_authorizable_xfrm(x)) { |
| 176 | struct xfrm_sec_ctx *ctx = x->security; | 238 | struct xfrm_sec_ctx *ctx = x->security; |
| 177 | 239 | ||
| 178 | if (!sid_set) { | 240 | if (sid_session == SECSID_NULL) { |
| 179 | *sid = ctx->ctx_sid; | 241 | sid_session = ctx->ctx_sid; |
| 180 | sid_set = 1; | ||
| 181 | |||
| 182 | if (!ckall) | 242 | if (!ckall) |
| 183 | break; | 243 | goto out; |
| 184 | } else if (*sid != ctx->ctx_sid) | 244 | } else if (sid_session != ctx->ctx_sid) { |
| 245 | *sid = SECSID_NULL; | ||
| 185 | return -EINVAL; | 246 | return -EINVAL; |
| 247 | } | ||
| 186 | } | 248 | } |
| 187 | } | 249 | } |
| 188 | } | 250 | } |
| 189 | 251 | ||
| 252 | out: | ||
| 253 | *sid = sid_session; | ||
| 190 | return 0; | 254 | return 0; |
| 191 | } | 255 | } |
| 192 | 256 | ||
| 193 | /* | 257 | /* |
| 194 | * Security blob allocation for xfrm_policy and xfrm_state | 258 | * LSM hook implementation that checks and/or returns the xfrm sid for the |
| 195 | * CTX does not have a meaningful value on input | 259 | * incoming packet. |
| 196 | */ | 260 | */ |
| 197 | static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, | 261 | int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) |
| 198 | struct xfrm_user_sec_ctx *uctx, u32 sid) | ||
| 199 | { | 262 | { |
| 200 | int rc = 0; | 263 | if (skb == NULL) { |
| 201 | const struct task_security_struct *tsec = current_security(); | 264 | *sid = SECSID_NULL; |
| 202 | struct xfrm_sec_ctx *ctx = NULL; | 265 | return 0; |
| 203 | char *ctx_str = NULL; | ||
| 204 | u32 str_len; | ||
| 205 | |||
| 206 | BUG_ON(uctx && sid); | ||
| 207 | |||
| 208 | if (!uctx) | ||
| 209 | goto not_from_user; | ||
| 210 | |||
| 211 | if (uctx->ctx_alg != XFRM_SC_ALG_SELINUX) | ||
| 212 | return -EINVAL; | ||
| 213 | |||
| 214 | str_len = uctx->ctx_len; | ||
| 215 | if (str_len >= PAGE_SIZE) | ||
| 216 | return -ENOMEM; | ||
| 217 | |||
| 218 | *ctxp = ctx = kmalloc(sizeof(*ctx) + | ||
| 219 | str_len + 1, | ||
| 220 | GFP_KERNEL); | ||
| 221 | |||
| 222 | if (!ctx) | ||
| 223 | return -ENOMEM; | ||
| 224 | |||
| 225 | ctx->ctx_doi = uctx->ctx_doi; | ||
| 226 | ctx->ctx_len = str_len; | ||
| 227 | ctx->ctx_alg = uctx->ctx_alg; | ||
| 228 | |||
| 229 | memcpy(ctx->ctx_str, | ||
| 230 | uctx+1, | ||
| 231 | str_len); | ||
| 232 | ctx->ctx_str[str_len] = 0; | ||
| 233 | rc = security_context_to_sid(ctx->ctx_str, | ||
| 234 | str_len, | ||
| 235 | &ctx->ctx_sid); | ||
| 236 | |||
| 237 | if (rc) | ||
| 238 | goto out; | ||
| 239 | |||
| 240 | /* | ||
| 241 | * Does the subject have permission to set security context? | ||
| 242 | */ | ||
| 243 | rc = avc_has_perm(tsec->sid, ctx->ctx_sid, | ||
| 244 | SECCLASS_ASSOCIATION, | ||
| 245 | ASSOCIATION__SETCONTEXT, NULL); | ||
| 246 | if (rc) | ||
| 247 | goto out; | ||
| 248 | |||
| 249 | return rc; | ||
| 250 | |||
| 251 | not_from_user: | ||
| 252 | rc = security_sid_to_context(sid, &ctx_str, &str_len); | ||
| 253 | if (rc) | ||
| 254 | goto out; | ||
| 255 | |||
| 256 | *ctxp = ctx = kmalloc(sizeof(*ctx) + | ||
| 257 | str_len, | ||
| 258 | GFP_ATOMIC); | ||
| 259 | |||
| 260 | if (!ctx) { | ||
| 261 | rc = -ENOMEM; | ||
| 262 | goto out; | ||
| 263 | } | 266 | } |
| 267 | return selinux_xfrm_skb_sid_ingress(skb, sid, ckall); | ||
| 268 | } | ||
| 264 | 269 | ||
| 265 | ctx->ctx_doi = XFRM_SC_DOI_LSM; | 270 | int selinux_xfrm_skb_sid(struct sk_buff *skb, u32 *sid) |
| 266 | ctx->ctx_alg = XFRM_SC_ALG_SELINUX; | 271 | { |
| 267 | ctx->ctx_sid = sid; | 272 | int rc; |
| 268 | ctx->ctx_len = str_len; | ||
| 269 | memcpy(ctx->ctx_str, | ||
| 270 | ctx_str, | ||
| 271 | str_len); | ||
| 272 | 273 | ||
| 273 | goto out2; | 274 | rc = selinux_xfrm_skb_sid_ingress(skb, sid, 0); |
| 275 | if (rc == 0 && *sid == SECSID_NULL) | ||
| 276 | *sid = selinux_xfrm_skb_sid_egress(skb); | ||
| 274 | 277 | ||
| 275 | out: | ||
| 276 | *ctxp = NULL; | ||
| 277 | kfree(ctx); | ||
| 278 | out2: | ||
| 279 | kfree(ctx_str); | ||
| 280 | return rc; | 278 | return rc; |
| 281 | } | 279 | } |
| 282 | 280 | ||
| 283 | /* | 281 | /* |
| 284 | * LSM hook implementation that allocs and transfers uctx spec to | 282 | * LSM hook implementation that allocs and transfers uctx spec to xfrm_policy. |
| 285 | * xfrm_policy. | ||
| 286 | */ | 283 | */ |
| 287 | int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, | 284 | int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, |
| 288 | struct xfrm_user_sec_ctx *uctx) | 285 | struct xfrm_user_sec_ctx *uctx) |
| 289 | { | 286 | { |
| 290 | int err; | 287 | return selinux_xfrm_alloc_user(ctxp, uctx); |
| 291 | |||
| 292 | BUG_ON(!uctx); | ||
| 293 | |||
| 294 | err = selinux_xfrm_sec_ctx_alloc(ctxp, uctx, 0); | ||
| 295 | if (err == 0) | ||
| 296 | atomic_inc(&selinux_xfrm_refcount); | ||
| 297 | |||
| 298 | return err; | ||
| 299 | } | 288 | } |
| 300 | 289 | ||
| 301 | |||
| 302 | /* | 290 | /* |
| 303 | * LSM hook implementation that copies security data structure from old to | 291 | * LSM hook implementation that copies security data structure from old to new |
| 304 | * new for policy cloning. | 292 | * for policy cloning. |
| 305 | */ | 293 | */ |
| 306 | int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, | 294 | int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, |
| 307 | struct xfrm_sec_ctx **new_ctxp) | 295 | struct xfrm_sec_ctx **new_ctxp) |
| 308 | { | 296 | { |
| 309 | struct xfrm_sec_ctx *new_ctx; | 297 | struct xfrm_sec_ctx *new_ctx; |
| 310 | 298 | ||
| 311 | if (old_ctx) { | 299 | if (!old_ctx) |
| 312 | new_ctx = kmalloc(sizeof(*old_ctx) + old_ctx->ctx_len, | 300 | return 0; |
| 313 | GFP_ATOMIC); | 301 | |
| 314 | if (!new_ctx) | 302 | new_ctx = kmemdup(old_ctx, sizeof(*old_ctx) + old_ctx->ctx_len, |
| 315 | return -ENOMEM; | 303 | GFP_ATOMIC); |
| 304 | if (!new_ctx) | ||
| 305 | return -ENOMEM; | ||
| 306 | atomic_inc(&selinux_xfrm_refcount); | ||
| 307 | *new_ctxp = new_ctx; | ||
| 316 | 308 | ||
| 317 | memcpy(new_ctx, old_ctx, sizeof(*new_ctx)); | ||
| 318 | memcpy(new_ctx->ctx_str, old_ctx->ctx_str, new_ctx->ctx_len); | ||
| 319 | atomic_inc(&selinux_xfrm_refcount); | ||
| 320 | *new_ctxp = new_ctx; | ||
| 321 | } | ||
| 322 | return 0; | 309 | return 0; |
| 323 | } | 310 | } |
| 324 | 311 | ||
| @@ -327,8 +314,7 @@ int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, | |||
| 327 | */ | 314 | */ |
| 328 | void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx) | 315 | void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx) |
| 329 | { | 316 | { |
| 330 | atomic_dec(&selinux_xfrm_refcount); | 317 | selinux_xfrm_free(ctx); |
| 331 | kfree(ctx); | ||
| 332 | } | 318 | } |
| 333 | 319 | ||
| 334 | /* | 320 | /* |
| @@ -336,31 +322,58 @@ void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx) | |||
| 336 | */ | 322 | */ |
| 337 | int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) | 323 | int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) |
| 338 | { | 324 | { |
| 339 | const struct task_security_struct *tsec = current_security(); | 325 | return selinux_xfrm_delete(ctx); |
| 340 | 326 | } | |
| 341 | if (!ctx) | ||
| 342 | return 0; | ||
| 343 | 327 | ||
| 344 | return avc_has_perm(tsec->sid, ctx->ctx_sid, | 328 | /* |
| 345 | SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, | 329 | * LSM hook implementation that allocates a xfrm_sec_state, populates it using |
| 346 | NULL); | 330 | * the supplied security context, and assigns it to the xfrm_state. |
| 331 | */ | ||
| 332 | int selinux_xfrm_state_alloc(struct xfrm_state *x, | ||
| 333 | struct xfrm_user_sec_ctx *uctx) | ||
| 334 | { | ||
| 335 | return selinux_xfrm_alloc_user(&x->security, uctx); | ||
| 347 | } | 336 | } |
| 348 | 337 | ||
| 349 | /* | 338 | /* |
| 350 | * LSM hook implementation that allocs and transfers sec_ctx spec to | 339 | * LSM hook implementation that allocates a xfrm_sec_state and populates based |
| 351 | * xfrm_state. | 340 | * on a secid. |
| 352 | */ | 341 | */ |
| 353 | int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx, | 342 | int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x, |
| 354 | u32 secid) | 343 | struct xfrm_sec_ctx *polsec, u32 secid) |
| 355 | { | 344 | { |
| 356 | int err; | 345 | int rc; |
| 346 | struct xfrm_sec_ctx *ctx; | ||
| 347 | char *ctx_str = NULL; | ||
| 348 | int str_len; | ||
| 349 | |||
| 350 | if (!polsec) | ||
| 351 | return 0; | ||
| 352 | |||
| 353 | if (secid == 0) | ||
| 354 | return -EINVAL; | ||
| 355 | |||
| 356 | rc = security_sid_to_context(secid, &ctx_str, &str_len); | ||
| 357 | if (rc) | ||
| 358 | return rc; | ||
| 357 | 359 | ||
| 358 | BUG_ON(!x); | 360 | ctx = kmalloc(sizeof(*ctx) + str_len, GFP_ATOMIC); |
| 361 | if (!ctx) { | ||
| 362 | rc = -ENOMEM; | ||
| 363 | goto out; | ||
| 364 | } | ||
| 359 | 365 | ||
| 360 | err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid); | 366 | ctx->ctx_doi = XFRM_SC_DOI_LSM; |
| 361 | if (err == 0) | 367 | ctx->ctx_alg = XFRM_SC_ALG_SELINUX; |
| 362 | atomic_inc(&selinux_xfrm_refcount); | 368 | ctx->ctx_sid = secid; |
| 363 | return err; | 369 | ctx->ctx_len = str_len; |
| 370 | memcpy(ctx->ctx_str, ctx_str, str_len); | ||
| 371 | |||
| 372 | x->security = ctx; | ||
| 373 | atomic_inc(&selinux_xfrm_refcount); | ||
| 374 | out: | ||
| 375 | kfree(ctx_str); | ||
| 376 | return rc; | ||
| 364 | } | 377 | } |
| 365 | 378 | ||
| 366 | /* | 379 | /* |
| @@ -368,24 +381,15 @@ int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uct | |||
| 368 | */ | 381 | */ |
| 369 | void selinux_xfrm_state_free(struct xfrm_state *x) | 382 | void selinux_xfrm_state_free(struct xfrm_state *x) |
| 370 | { | 383 | { |
| 371 | atomic_dec(&selinux_xfrm_refcount); | 384 | selinux_xfrm_free(x->security); |
| 372 | kfree(x->security); | ||
| 373 | } | 385 | } |
| 374 | 386 | ||
| 375 | /* | 387 | /* |
| 376 | * LSM hook implementation that authorizes deletion of labeled SAs. | 388 | * LSM hook implementation that authorizes deletion of labeled SAs. |
| 377 | */ | 389 | */ |
| 378 | int selinux_xfrm_state_delete(struct xfrm_state *x) | 390 | int selinux_xfrm_state_delete(struct xfrm_state *x) |
| 379 | { | 391 | { |
| 380 | const struct task_security_struct *tsec = current_security(); | 392 | return selinux_xfrm_delete(x->security); |
| 381 | struct xfrm_sec_ctx *ctx = x->security; | ||
| 382 | |||
| 383 | if (!ctx) | ||
| 384 | return 0; | ||
| 385 | |||
| 386 | return avc_has_perm(tsec->sid, ctx->ctx_sid, | ||
| 387 | SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, | ||
| 388 | NULL); | ||
| 389 | } | 393 | } |
| 390 | 394 | ||
| 391 | /* | 395 | /* |
| @@ -395,14 +399,12 @@ int selinux_xfrm_state_delete(struct xfrm_state *x) | |||
| 395 | * we need to check for unlabelled access since this may not have | 399 | * we need to check for unlabelled access since this may not have |
| 396 | * gone thru the IPSec process. | 400 | * gone thru the IPSec process. |
| 397 | */ | 401 | */ |
| 398 | int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, | 402 | int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb, |
| 399 | struct common_audit_data *ad) | 403 | struct common_audit_data *ad) |
| 400 | { | 404 | { |
| 401 | int i, rc = 0; | 405 | int i; |
| 402 | struct sec_path *sp; | 406 | struct sec_path *sp = skb->sp; |
| 403 | u32 sel_sid = SECINITSID_UNLABELED; | 407 | u32 peer_sid = SECINITSID_UNLABELED; |
| 404 | |||
| 405 | sp = skb->sp; | ||
| 406 | 408 | ||
| 407 | if (sp) { | 409 | if (sp) { |
| 408 | for (i = 0; i < sp->len; i++) { | 410 | for (i = 0; i < sp->len; i++) { |
| @@ -410,23 +412,17 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, | |||
| 410 | 412 | ||
| 411 | if (x && selinux_authorizable_xfrm(x)) { | 413 | if (x && selinux_authorizable_xfrm(x)) { |
| 412 | struct xfrm_sec_ctx *ctx = x->security; | 414 | struct xfrm_sec_ctx *ctx = x->security; |
| 413 | sel_sid = ctx->ctx_sid; | 415 | peer_sid = ctx->ctx_sid; |
| 414 | break; | 416 | break; |
| 415 | } | 417 | } |
| 416 | } | 418 | } |
| 417 | } | 419 | } |
| 418 | 420 | ||
| 419 | /* | 421 | /* This check even when there's no association involved is intended, |
| 420 | * This check even when there's no association involved is | 422 | * according to Trent Jaeger, to make sure a process can't engage in |
| 421 | * intended, according to Trent Jaeger, to make sure a | 423 | * non-IPsec communication unless explicitly allowed by policy. */ |
| 422 | * process can't engage in non-ipsec communication unless | 424 | return avc_has_perm(sk_sid, peer_sid, |
| 423 | * explicitly allowed by policy. | 425 | SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, ad); |
| 424 | */ | ||
| 425 | |||
| 426 | rc = avc_has_perm(isec_sid, sel_sid, SECCLASS_ASSOCIATION, | ||
| 427 | ASSOCIATION__RECVFROM, ad); | ||
| 428 | |||
| 429 | return rc; | ||
| 430 | } | 426 | } |
| 431 | 427 | ||
| 432 | /* | 428 | /* |
| @@ -436,49 +432,38 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, | |||
| 436 | * If we do have a authorizable security association, then it has already been | 432 | * If we do have a authorizable security association, then it has already been |
| 437 | * checked in the selinux_xfrm_state_pol_flow_match hook above. | 433 | * checked in the selinux_xfrm_state_pol_flow_match hook above. |
| 438 | */ | 434 | */ |
| 439 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, | 435 | int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb, |
| 440 | struct common_audit_data *ad, u8 proto) | 436 | struct common_audit_data *ad, u8 proto) |
| 441 | { | 437 | { |
| 442 | struct dst_entry *dst; | 438 | struct dst_entry *dst; |
| 443 | int rc = 0; | ||
| 444 | |||
| 445 | dst = skb_dst(skb); | ||
| 446 | |||
| 447 | if (dst) { | ||
| 448 | struct dst_entry *dst_test; | ||
| 449 | |||
| 450 | for (dst_test = dst; dst_test != NULL; | ||
| 451 | dst_test = dst_test->child) { | ||
| 452 | struct xfrm_state *x = dst_test->xfrm; | ||
| 453 | |||
| 454 | if (x && selinux_authorizable_xfrm(x)) | ||
| 455 | goto out; | ||
| 456 | } | ||
| 457 | } | ||
| 458 | 439 | ||
| 459 | switch (proto) { | 440 | switch (proto) { |
| 460 | case IPPROTO_AH: | 441 | case IPPROTO_AH: |
| 461 | case IPPROTO_ESP: | 442 | case IPPROTO_ESP: |
| 462 | case IPPROTO_COMP: | 443 | case IPPROTO_COMP: |
| 463 | /* | 444 | /* We should have already seen this packet once before it |
| 464 | * We should have already seen this packet once before | 445 | * underwent xfrm(s). No need to subject it to the unlabeled |
| 465 | * it underwent xfrm(s). No need to subject it to the | 446 | * check. */ |
| 466 | * unlabeled check. | 447 | return 0; |
| 467 | */ | ||
| 468 | goto out; | ||
| 469 | default: | 448 | default: |
| 470 | break; | 449 | break; |
| 471 | } | 450 | } |
| 472 | 451 | ||
| 473 | /* | 452 | dst = skb_dst(skb); |
| 474 | * This check even when there's no association involved is | 453 | if (dst) { |
| 475 | * intended, according to Trent Jaeger, to make sure a | 454 | struct dst_entry *iter; |
| 476 | * process can't engage in non-ipsec communication unless | ||
| 477 | * explicitly allowed by policy. | ||
| 478 | */ | ||
| 479 | 455 | ||
| 480 | rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, | 456 | for (iter = dst; iter != NULL; iter = iter->child) { |
| 481 | ASSOCIATION__SENDTO, ad); | 457 | struct xfrm_state *x = iter->xfrm; |
| 482 | out: | 458 | |
| 483 | return rc; | 459 | if (x && selinux_authorizable_xfrm(x)) |
| 460 | return 0; | ||
| 461 | } | ||
| 462 | } | ||
| 463 | |||
| 464 | /* This check even when there's no association involved is intended, | ||
| 465 | * according to Trent Jaeger, to make sure a process can't engage in | ||
| 466 | * non-IPsec communication unless explicitly allowed by policy. */ | ||
| 467 | return avc_has_perm(sk_sid, SECINITSID_UNLABELED, | ||
| 468 | SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, ad); | ||
| 484 | } | 469 | } |
