diff options
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r-- | security/selinux/hooks.c | 253 |
1 files changed, 189 insertions, 64 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 5b5231068516..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, |
@@ -3928,7 +3990,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
3928 | if (snum) { | 3990 | if (snum) { |
3929 | int low, high; | 3991 | int low, high; |
3930 | 3992 | ||
3931 | inet_get_local_port_range(&low, &high); | 3993 | inet_get_local_port_range(sock_net(sk), &low, &high); |
3932 | 3994 | ||
3933 | if (snum < max(PROT_SOCK, low) || snum > high) { | 3995 | if (snum < max(PROT_SOCK, low) || snum > high) { |
3934 | err = sel_netport_sid(sk->sk_protocol, | 3996 | err = sel_netport_sid(sk->sk_protocol, |
@@ -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 | ||
@@ -4667,7 +4724,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, | |||
4667 | return NF_ACCEPT; | 4724 | return NF_ACCEPT; |
4668 | } | 4725 | } |
4669 | 4726 | ||
4670 | static unsigned int selinux_ipv4_forward(unsigned int hooknum, | 4727 | static unsigned int selinux_ipv4_forward(const struct nf_hook_ops *ops, |
4671 | struct sk_buff *skb, | 4728 | struct sk_buff *skb, |
4672 | const struct net_device *in, | 4729 | const struct net_device *in, |
4673 | const struct net_device *out, | 4730 | const struct net_device *out, |
@@ -4677,7 +4734,7 @@ static unsigned int selinux_ipv4_forward(unsigned int hooknum, | |||
4677 | } | 4734 | } |
4678 | 4735 | ||
4679 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 4736 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
4680 | static unsigned int selinux_ipv6_forward(unsigned int hooknum, | 4737 | static unsigned int selinux_ipv6_forward(const struct nf_hook_ops *ops, |
4681 | struct sk_buff *skb, | 4738 | struct sk_buff *skb, |
4682 | const struct net_device *in, | 4739 | const struct net_device *in, |
4683 | const struct net_device *out, | 4740 | const struct net_device *out, |
@@ -4690,6 +4747,7 @@ static unsigned int selinux_ipv6_forward(unsigned int hooknum, | |||
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; |
@@ -4709,7 +4786,7 @@ static unsigned int selinux_ip_output(struct sk_buff *skb, | |||
4709 | return NF_ACCEPT; | 4786 | return NF_ACCEPT; |
4710 | } | 4787 | } |
4711 | 4788 | ||
4712 | static unsigned int selinux_ipv4_output(unsigned int hooknum, | 4789 | static unsigned int selinux_ipv4_output(const struct nf_hook_ops *ops, |
4713 | struct sk_buff *skb, | 4790 | struct sk_buff *skb, |
4714 | const struct net_device *in, | 4791 | const struct net_device *in, |
4715 | const struct net_device *out, | 4792 | const struct net_device *out, |
@@ -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; |
@@ -4836,7 +4960,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
4836 | return NF_ACCEPT; | 4960 | return NF_ACCEPT; |
4837 | } | 4961 | } |
4838 | 4962 | ||
4839 | static unsigned int selinux_ipv4_postroute(unsigned int hooknum, | 4963 | static unsigned int selinux_ipv4_postroute(const struct nf_hook_ops *ops, |
4840 | struct sk_buff *skb, | 4964 | struct sk_buff *skb, |
4841 | const struct net_device *in, | 4965 | const struct net_device *in, |
4842 | const struct net_device *out, | 4966 | const struct net_device *out, |
@@ -4846,7 +4970,7 @@ static unsigned int selinux_ipv4_postroute(unsigned int hooknum, | |||
4846 | } | 4970 | } |
4847 | 4971 | ||
4848 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 4972 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
4849 | static unsigned int selinux_ipv6_postroute(unsigned int hooknum, | 4973 | static unsigned int selinux_ipv6_postroute(const struct nf_hook_ops *ops, |
4850 | struct sk_buff *skb, | 4974 | struct sk_buff *skb, |
4851 | const struct net_device *in, | 4975 | const struct net_device *in, |
4852 | const struct net_device *out, | 4976 | const struct net_device *out, |
@@ -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, |