diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-01-30 17:32:24 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-01-30 17:32:24 -0500 |
| commit | 44c3b59102e3ecc7a01e9811862633e670595e51 (patch) | |
| tree | 5bf397b2b4bd8fc08c59ad5f9f9c83874259da48 /security/selinux/hooks.c | |
| parent | 3b470ac43fcd9848fa65e58e54875ad75be61cec (diff) | |
| parent | f71ea9ddf0ff110f3fcbb89a46686bfba264014c (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6:
security: compile capabilities by default
selinux: make selinux_set_mnt_opts() static
SELinux: Add warning messages on network denial due to error
SELinux: Add network ingress and egress control permission checks
NetLabel: Add auditing to the static labeling mechanism
NetLabel: Introduce static network labels for unlabeled connections
SELinux: Allow NetLabel to directly cache SIDs
SELinux: Enable dynamic enable/disable of the network access checks
SELinux: Better integration between peer labeling subsystems
SELinux: Add a new peer class and permissions to the Flask definitions
SELinux: Add a capabilities bitmap to SELinux policy version 22
SELinux: Add a network node caching mechanism similar to the sel_netif_*() functions
SELinux: Only store the network interface's ifindex
SELinux: Convert the netif code to use ifindex values
NetLabel: Add IP address family information to the netlbl_skbuff_getattr() function
NetLabel: Add secid token support to the NetLabel secattr struct
NetLabel: Consolidate the LSM domain mapping/hashing locks
NetLabel: Cleanup the LSM domain hash functions
NetLabel: Remove unneeded RCU read locks
Diffstat (limited to 'security/selinux/hooks.c')
| -rw-r--r-- | security/selinux/hooks.c | 667 |
1 files changed, 450 insertions, 217 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 64d414efb404..be6de0b8734f 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -12,8 +12,8 @@ | |||
| 12 | * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> | 12 | * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> |
| 13 | * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. | 13 | * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. |
| 14 | * <dgoeddel@trustedcs.com> | 14 | * <dgoeddel@trustedcs.com> |
| 15 | * Copyright (C) 2006 Hewlett-Packard Development Company, L.P. | 15 | * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. |
| 16 | * Paul Moore, <paul.moore@hp.com> | 16 | * Paul Moore <paul.moore@hp.com> |
| 17 | * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd. | 17 | * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd. |
| 18 | * Yuichi Nakamura <ynakam@hitachisoft.jp> | 18 | * Yuichi Nakamura <ynakam@hitachisoft.jp> |
| 19 | * | 19 | * |
| @@ -50,8 +50,11 @@ | |||
| 50 | #include <net/icmp.h> | 50 | #include <net/icmp.h> |
| 51 | #include <net/ip.h> /* for local_port_range[] */ | 51 | #include <net/ip.h> /* for local_port_range[] */ |
| 52 | #include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */ | 52 | #include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */ |
| 53 | #include <net/net_namespace.h> | ||
| 54 | #include <net/netlabel.h> | ||
| 53 | #include <asm/uaccess.h> | 55 | #include <asm/uaccess.h> |
| 54 | #include <asm/ioctls.h> | 56 | #include <asm/ioctls.h> |
| 57 | #include <asm/atomic.h> | ||
| 55 | #include <linux/bitops.h> | 58 | #include <linux/bitops.h> |
| 56 | #include <linux/interrupt.h> | 59 | #include <linux/interrupt.h> |
| 57 | #include <linux/netdevice.h> /* for network interface checks */ | 60 | #include <linux/netdevice.h> /* for network interface checks */ |
| @@ -76,6 +79,7 @@ | |||
| 76 | #include "avc.h" | 79 | #include "avc.h" |
| 77 | #include "objsec.h" | 80 | #include "objsec.h" |
| 78 | #include "netif.h" | 81 | #include "netif.h" |
| 82 | #include "netnode.h" | ||
| 79 | #include "xfrm.h" | 83 | #include "xfrm.h" |
| 80 | #include "netlabel.h" | 84 | #include "netlabel.h" |
| 81 | 85 | ||
| @@ -89,6 +93,9 @@ extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); | |||
| 89 | extern int selinux_compat_net; | 93 | extern int selinux_compat_net; |
| 90 | extern struct security_operations *security_ops; | 94 | extern struct security_operations *security_ops; |
| 91 | 95 | ||
| 96 | /* SECMARK reference count */ | ||
| 97 | atomic_t selinux_secmark_refcount = ATOMIC_INIT(0); | ||
| 98 | |||
| 92 | #ifdef CONFIG_SECURITY_SELINUX_DEVELOP | 99 | #ifdef CONFIG_SECURITY_SELINUX_DEVELOP |
| 93 | int selinux_enforcing = 0; | 100 | int selinux_enforcing = 0; |
| 94 | 101 | ||
| @@ -155,6 +162,21 @@ getsecurity_exit: | |||
| 155 | return len; | 162 | return len; |
| 156 | } | 163 | } |
| 157 | 164 | ||
| 165 | /** | ||
| 166 | * selinux_secmark_enabled - Check to see if SECMARK is currently enabled | ||
| 167 | * | ||
| 168 | * Description: | ||
| 169 | * This function checks the SECMARK reference counter to see if any SECMARK | ||
| 170 | * targets are currently configured, if the reference counter is greater than | ||
| 171 | * zero SECMARK is considered to be enabled. Returns true (1) if SECMARK is | ||
| 172 | * enabled, false (0) if SECMARK is disabled. | ||
| 173 | * | ||
| 174 | */ | ||
| 175 | static int selinux_secmark_enabled(void) | ||
| 176 | { | ||
| 177 | return (atomic_read(&selinux_secmark_refcount) > 0); | ||
| 178 | } | ||
| 179 | |||
| 158 | /* Allocate and free functions for each kind of security blob. */ | 180 | /* Allocate and free functions for each kind of security blob. */ |
| 159 | 181 | ||
| 160 | static int task_alloc_security(struct task_struct *task) | 182 | static int task_alloc_security(struct task_struct *task) |
| @@ -561,8 +583,8 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag, | |||
| 561 | * Allow filesystems with binary mount data to explicitly set mount point | 583 | * Allow filesystems with binary mount data to explicitly set mount point |
| 562 | * labeling information. | 584 | * labeling information. |
| 563 | */ | 585 | */ |
| 564 | int selinux_set_mnt_opts(struct super_block *sb, char **mount_options, | 586 | static int selinux_set_mnt_opts(struct super_block *sb, char **mount_options, |
| 565 | int *flags, int num_opts) | 587 | int *flags, int num_opts) |
| 566 | { | 588 | { |
| 567 | int rc = 0, i; | 589 | int rc = 0, i; |
| 568 | struct task_security_struct *tsec = current->security; | 590 | struct task_security_struct *tsec = current->security; |
| @@ -3395,7 +3417,7 @@ out: | |||
| 3395 | #endif /* IPV6 */ | 3417 | #endif /* IPV6 */ |
| 3396 | 3418 | ||
| 3397 | static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, | 3419 | static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, |
| 3398 | char **addrp, int *len, int src, u8 *proto) | 3420 | char **addrp, int src, u8 *proto) |
| 3399 | { | 3421 | { |
| 3400 | int ret = 0; | 3422 | int ret = 0; |
| 3401 | 3423 | ||
| @@ -3404,7 +3426,6 @@ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, | |||
| 3404 | ret = selinux_parse_skb_ipv4(skb, ad, proto); | 3426 | ret = selinux_parse_skb_ipv4(skb, ad, proto); |
| 3405 | if (ret || !addrp) | 3427 | if (ret || !addrp) |
| 3406 | break; | 3428 | break; |
| 3407 | *len = 4; | ||
| 3408 | *addrp = (char *)(src ? &ad->u.net.v4info.saddr : | 3429 | *addrp = (char *)(src ? &ad->u.net.v4info.saddr : |
| 3409 | &ad->u.net.v4info.daddr); | 3430 | &ad->u.net.v4info.daddr); |
| 3410 | break; | 3431 | break; |
| @@ -3414,7 +3435,6 @@ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, | |||
| 3414 | ret = selinux_parse_skb_ipv6(skb, ad, proto); | 3435 | ret = selinux_parse_skb_ipv6(skb, ad, proto); |
| 3415 | if (ret || !addrp) | 3436 | if (ret || !addrp) |
| 3416 | break; | 3437 | break; |
| 3417 | *len = 16; | ||
| 3418 | *addrp = (char *)(src ? &ad->u.net.v6info.saddr : | 3438 | *addrp = (char *)(src ? &ad->u.net.v6info.saddr : |
| 3419 | &ad->u.net.v6info.daddr); | 3439 | &ad->u.net.v6info.daddr); |
| 3420 | break; | 3440 | break; |
| @@ -3423,36 +3443,48 @@ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, | |||
| 3423 | break; | 3443 | break; |
| 3424 | } | 3444 | } |
| 3425 | 3445 | ||
| 3446 | if (unlikely(ret)) | ||
| 3447 | printk(KERN_WARNING | ||
| 3448 | "SELinux: failure in selinux_parse_skb()," | ||
| 3449 | " unable to parse packet\n"); | ||
| 3450 | |||
| 3426 | return ret; | 3451 | return ret; |
| 3427 | } | 3452 | } |
| 3428 | 3453 | ||
| 3429 | /** | 3454 | /** |
| 3430 | * selinux_skb_extlbl_sid - Determine the external label of a packet | 3455 | * selinux_skb_peerlbl_sid - Determine the peer label of a packet |
| 3431 | * @skb: the packet | 3456 | * @skb: the packet |
| 3432 | * @sid: the packet's SID | 3457 | * @family: protocol family |
| 3458 | * @sid: the packet's peer label SID | ||
| 3433 | * | 3459 | * |
| 3434 | * Description: | 3460 | * Description: |
| 3435 | * Check the various different forms of external packet labeling and determine | 3461 | * Check the various different forms of network peer labeling and determine |
| 3436 | * the external SID for the packet. If only one form of external labeling is | 3462 | * the peer label/SID for the packet; most of the magic actually occurs in |
| 3437 | * present then it is used, if both labeled IPsec and NetLabel labels are | 3463 | * the security server function security_net_peersid_cmp(). The function |
| 3438 | * present then the SELinux type information is taken from the labeled IPsec | 3464 | * returns zero if the value in @sid is valid (although it may be SECSID_NULL) |
| 3439 | * SA and the MLS sensitivity label information is taken from the NetLabel | 3465 | * or -EACCES if @sid is invalid due to inconsistencies with the different |
| 3440 | * security attributes. This bit of "magic" is done in the call to | 3466 | * peer labels. |
| 3441 | * selinux_netlbl_skbuff_getsid(). | ||
| 3442 | * | 3467 | * |
| 3443 | */ | 3468 | */ |
| 3444 | static void selinux_skb_extlbl_sid(struct sk_buff *skb, u32 *sid) | 3469 | static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid) |
| 3445 | { | 3470 | { |
| 3471 | int err; | ||
| 3446 | u32 xfrm_sid; | 3472 | u32 xfrm_sid; |
| 3447 | u32 nlbl_sid; | 3473 | u32 nlbl_sid; |
| 3474 | u32 nlbl_type; | ||
| 3448 | 3475 | ||
| 3449 | selinux_skb_xfrm_sid(skb, &xfrm_sid); | 3476 | selinux_skb_xfrm_sid(skb, &xfrm_sid); |
| 3450 | if (selinux_netlbl_skbuff_getsid(skb, | 3477 | selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid); |
| 3451 | (xfrm_sid == SECSID_NULL ? | 3478 | |
| 3452 | SECINITSID_NETMSG : xfrm_sid), | 3479 | err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid); |
| 3453 | &nlbl_sid) != 0) | 3480 | if (unlikely(err)) { |
| 3454 | nlbl_sid = SECSID_NULL; | 3481 | printk(KERN_WARNING |
| 3455 | *sid = (nlbl_sid == SECSID_NULL ? xfrm_sid : nlbl_sid); | 3482 | "SELinux: failure in selinux_skb_peerlbl_sid()," |
| 3483 | " unable to determine packet's peer label\n"); | ||
| 3484 | return -EACCES; | ||
| 3485 | } | ||
| 3486 | |||
| 3487 | return 0; | ||
| 3456 | } | 3488 | } |
| 3457 | 3489 | ||
| 3458 | /* socket security operations */ | 3490 | /* socket security operations */ |
| @@ -3518,6 +3550,7 @@ static int selinux_socket_post_create(struct socket *sock, int family, | |||
| 3518 | if (sock->sk) { | 3550 | if (sock->sk) { |
| 3519 | sksec = sock->sk->sk_security; | 3551 | sksec = sock->sk->sk_security; |
| 3520 | sksec->sid = isec->sid; | 3552 | sksec->sid = isec->sid; |
| 3553 | sksec->sclass = isec->sclass; | ||
| 3521 | err = selinux_netlbl_socket_post_create(sock); | 3554 | err = selinux_netlbl_socket_post_create(sock); |
| 3522 | } | 3555 | } |
| 3523 | 3556 | ||
| @@ -3610,7 +3643,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
| 3610 | break; | 3643 | break; |
| 3611 | } | 3644 | } |
| 3612 | 3645 | ||
| 3613 | err = security_node_sid(family, addrp, addrlen, &sid); | 3646 | err = sel_netnode_sid(addrp, family, &sid); |
| 3614 | if (err) | 3647 | if (err) |
| 3615 | goto out; | 3648 | goto out; |
| 3616 | 3649 | ||
| @@ -3821,131 +3854,182 @@ static int selinux_socket_unix_may_send(struct socket *sock, | |||
| 3821 | return 0; | 3854 | return 0; |
| 3822 | } | 3855 | } |
| 3823 | 3856 | ||
| 3824 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | 3857 | static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, |
| 3825 | struct avc_audit_data *ad, u16 family, char *addrp, int len) | 3858 | u32 peer_sid, |
| 3859 | struct avc_audit_data *ad) | ||
| 3826 | { | 3860 | { |
| 3827 | int err = 0; | 3861 | int err; |
| 3828 | u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0; | 3862 | u32 if_sid; |
| 3829 | struct socket *sock; | 3863 | u32 node_sid; |
| 3830 | u16 sock_class = 0; | ||
| 3831 | u32 sock_sid = 0; | ||
| 3832 | |||
| 3833 | read_lock_bh(&sk->sk_callback_lock); | ||
| 3834 | sock = sk->sk_socket; | ||
| 3835 | if (sock) { | ||
| 3836 | struct inode *inode; | ||
| 3837 | inode = SOCK_INODE(sock); | ||
| 3838 | if (inode) { | ||
| 3839 | struct inode_security_struct *isec; | ||
| 3840 | isec = inode->i_security; | ||
| 3841 | sock_sid = isec->sid; | ||
| 3842 | sock_class = isec->sclass; | ||
| 3843 | } | ||
| 3844 | } | ||
| 3845 | read_unlock_bh(&sk->sk_callback_lock); | ||
| 3846 | if (!sock_sid) | ||
| 3847 | goto out; | ||
| 3848 | 3864 | ||
| 3849 | if (!skb->dev) | 3865 | err = sel_netif_sid(ifindex, &if_sid); |
| 3850 | goto out; | 3866 | if (err) |
| 3867 | return err; | ||
| 3868 | err = avc_has_perm(peer_sid, if_sid, | ||
| 3869 | SECCLASS_NETIF, NETIF__INGRESS, ad); | ||
| 3870 | if (err) | ||
| 3871 | return err; | ||
| 3851 | 3872 | ||
| 3852 | err = sel_netif_sids(skb->dev, &if_sid, NULL); | 3873 | err = sel_netnode_sid(addrp, family, &node_sid); |
| 3853 | if (err) | 3874 | if (err) |
| 3854 | goto out; | 3875 | return err; |
| 3876 | return avc_has_perm(peer_sid, node_sid, | ||
| 3877 | SECCLASS_NODE, NODE__RECVFROM, ad); | ||
| 3878 | } | ||
| 3879 | |||
| 3880 | static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk, | ||
| 3881 | struct sk_buff *skb, | ||
| 3882 | struct avc_audit_data *ad, | ||
| 3883 | u16 family, | ||
| 3884 | char *addrp) | ||
| 3885 | { | ||
| 3886 | int err; | ||
| 3887 | struct sk_security_struct *sksec = sk->sk_security; | ||
| 3888 | u16 sk_class; | ||
| 3889 | u32 netif_perm, node_perm, recv_perm; | ||
| 3890 | u32 port_sid, node_sid, if_sid, sk_sid; | ||
| 3855 | 3891 | ||
| 3856 | switch (sock_class) { | 3892 | sk_sid = sksec->sid; |
| 3893 | sk_class = sksec->sclass; | ||
| 3894 | |||
| 3895 | switch (sk_class) { | ||
| 3857 | case SECCLASS_UDP_SOCKET: | 3896 | case SECCLASS_UDP_SOCKET: |
| 3858 | netif_perm = NETIF__UDP_RECV; | 3897 | netif_perm = NETIF__UDP_RECV; |
| 3859 | node_perm = NODE__UDP_RECV; | 3898 | node_perm = NODE__UDP_RECV; |
| 3860 | recv_perm = UDP_SOCKET__RECV_MSG; | 3899 | recv_perm = UDP_SOCKET__RECV_MSG; |
| 3861 | break; | 3900 | break; |
| 3862 | |||
| 3863 | case SECCLASS_TCP_SOCKET: | 3901 | case SECCLASS_TCP_SOCKET: |
| 3864 | netif_perm = NETIF__TCP_RECV; | 3902 | netif_perm = NETIF__TCP_RECV; |
| 3865 | node_perm = NODE__TCP_RECV; | 3903 | node_perm = NODE__TCP_RECV; |
| 3866 | recv_perm = TCP_SOCKET__RECV_MSG; | 3904 | recv_perm = TCP_SOCKET__RECV_MSG; |
| 3867 | break; | 3905 | break; |
| 3868 | |||
| 3869 | case SECCLASS_DCCP_SOCKET: | 3906 | case SECCLASS_DCCP_SOCKET: |
| 3870 | netif_perm = NETIF__DCCP_RECV; | 3907 | netif_perm = NETIF__DCCP_RECV; |
| 3871 | node_perm = NODE__DCCP_RECV; | 3908 | node_perm = NODE__DCCP_RECV; |
| 3872 | recv_perm = DCCP_SOCKET__RECV_MSG; | 3909 | recv_perm = DCCP_SOCKET__RECV_MSG; |
| 3873 | break; | 3910 | break; |
| 3874 | |||
| 3875 | default: | 3911 | default: |
| 3876 | netif_perm = NETIF__RAWIP_RECV; | 3912 | netif_perm = NETIF__RAWIP_RECV; |
| 3877 | node_perm = NODE__RAWIP_RECV; | 3913 | node_perm = NODE__RAWIP_RECV; |
| 3914 | recv_perm = 0; | ||
| 3878 | break; | 3915 | break; |
| 3879 | } | 3916 | } |
| 3880 | 3917 | ||
| 3881 | err = avc_has_perm(sock_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); | 3918 | err = sel_netif_sid(skb->iif, &if_sid); |
| 3882 | if (err) | 3919 | if (err) |
| 3883 | goto out; | 3920 | return err; |
| 3884 | 3921 | err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); | |
| 3885 | err = security_node_sid(family, addrp, len, &node_sid); | ||
| 3886 | if (err) | 3922 | if (err) |
| 3887 | goto out; | 3923 | return err; |
| 3888 | 3924 | ||
| 3889 | err = avc_has_perm(sock_sid, node_sid, SECCLASS_NODE, node_perm, ad); | 3925 | err = sel_netnode_sid(addrp, family, &node_sid); |
| 3890 | if (err) | 3926 | if (err) |
| 3891 | goto out; | 3927 | return err; |
| 3928 | err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad); | ||
| 3929 | if (err) | ||
| 3930 | return err; | ||
| 3892 | 3931 | ||
| 3893 | if (recv_perm) { | 3932 | if (!recv_perm) |
| 3894 | u32 port_sid; | 3933 | return 0; |
| 3934 | err = security_port_sid(sk->sk_family, sk->sk_type, | ||
| 3935 | sk->sk_protocol, ntohs(ad->u.net.sport), | ||
| 3936 | &port_sid); | ||
| 3937 | if (unlikely(err)) { | ||
| 3938 | printk(KERN_WARNING | ||
| 3939 | "SELinux: failure in" | ||
| 3940 | " selinux_sock_rcv_skb_iptables_compat()," | ||
| 3941 | " network port label not found\n"); | ||
| 3942 | return err; | ||
| 3943 | } | ||
| 3944 | return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad); | ||
| 3945 | } | ||
| 3895 | 3946 | ||
| 3896 | err = security_port_sid(sk->sk_family, sk->sk_type, | 3947 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, |
| 3897 | sk->sk_protocol, ntohs(ad->u.net.sport), | 3948 | struct avc_audit_data *ad, |
| 3898 | &port_sid); | 3949 | u16 family, char *addrp) |
| 3899 | if (err) | 3950 | { |
| 3900 | goto out; | 3951 | int err; |
| 3952 | struct sk_security_struct *sksec = sk->sk_security; | ||
| 3953 | u32 peer_sid; | ||
| 3954 | u32 sk_sid = sksec->sid; | ||
| 3901 | 3955 | ||
| 3902 | err = avc_has_perm(sock_sid, port_sid, | 3956 | if (selinux_compat_net) |
| 3903 | sock_class, recv_perm, ad); | 3957 | err = selinux_sock_rcv_skb_iptables_compat(sk, skb, ad, |
| 3958 | family, addrp); | ||
| 3959 | else | ||
| 3960 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, | ||
| 3961 | PACKET__RECV, ad); | ||
| 3962 | if (err) | ||
| 3963 | return err; | ||
| 3964 | |||
| 3965 | if (selinux_policycap_netpeer) { | ||
| 3966 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); | ||
| 3967 | if (err) | ||
| 3968 | return err; | ||
| 3969 | err = avc_has_perm(sk_sid, peer_sid, | ||
| 3970 | SECCLASS_PEER, PEER__RECV, ad); | ||
| 3971 | } else { | ||
| 3972 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, ad); | ||
| 3973 | if (err) | ||
| 3974 | return err; | ||
| 3975 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, ad); | ||
| 3904 | } | 3976 | } |
| 3905 | 3977 | ||
| 3906 | out: | ||
| 3907 | return err; | 3978 | return err; |
| 3908 | } | 3979 | } |
| 3909 | 3980 | ||
| 3910 | static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | 3981 | static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) |
| 3911 | { | 3982 | { |
| 3912 | u16 family; | 3983 | int err; |
| 3913 | char *addrp; | ||
| 3914 | int len, err = 0; | ||
| 3915 | struct avc_audit_data ad; | ||
| 3916 | struct sk_security_struct *sksec = sk->sk_security; | 3984 | struct sk_security_struct *sksec = sk->sk_security; |
| 3985 | u16 family = sk->sk_family; | ||
| 3986 | u32 sk_sid = sksec->sid; | ||
| 3987 | struct avc_audit_data ad; | ||
| 3988 | char *addrp; | ||
| 3917 | 3989 | ||
| 3918 | family = sk->sk_family; | ||
| 3919 | if (family != PF_INET && family != PF_INET6) | 3990 | if (family != PF_INET && family != PF_INET6) |
| 3920 | goto out; | 3991 | return 0; |
| 3921 | 3992 | ||
| 3922 | /* Handle mapped IPv4 packets arriving via IPv6 sockets */ | 3993 | /* Handle mapped IPv4 packets arriving via IPv6 sockets */ |
| 3923 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | 3994 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) |
| 3924 | family = PF_INET; | 3995 | family = PF_INET; |
| 3925 | 3996 | ||
| 3926 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3997 | AVC_AUDIT_DATA_INIT(&ad, NET); |
| 3927 | ad.u.net.netif = skb->dev ? skb->dev->name : "[unknown]"; | 3998 | ad.u.net.netif = skb->iif; |
| 3928 | ad.u.net.family = family; | 3999 | ad.u.net.family = family; |
| 3929 | 4000 | err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); | |
| 3930 | err = selinux_parse_skb(skb, &ad, &addrp, &len, 1, NULL); | ||
| 3931 | if (err) | 4001 | if (err) |
| 3932 | goto out; | 4002 | return err; |
| 3933 | 4003 | ||
| 3934 | if (selinux_compat_net) | 4004 | /* If any sort of compatibility mode is enabled then handoff processing |
| 3935 | err = selinux_sock_rcv_skb_compat(sk, skb, &ad, family, | 4005 | * to the selinux_sock_rcv_skb_compat() function to deal with the |
| 3936 | addrp, len); | 4006 | * special handling. We do this in an attempt to keep this function |
| 3937 | else | 4007 | * as fast and as clean as possible. */ |
| 3938 | err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET, | 4008 | if (selinux_compat_net || !selinux_policycap_netpeer) |
| 3939 | PACKET__RECV, &ad); | 4009 | return selinux_sock_rcv_skb_compat(sk, skb, &ad, |
| 3940 | if (err) | 4010 | family, addrp); |
| 3941 | goto out; | ||
| 3942 | 4011 | ||
| 3943 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, &ad); | 4012 | if (netlbl_enabled() || selinux_xfrm_enabled()) { |
| 3944 | if (err) | 4013 | u32 peer_sid; |
| 3945 | goto out; | 4014 | |
| 4015 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); | ||
| 4016 | if (err) | ||
| 4017 | return err; | ||
| 4018 | err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family, | ||
| 4019 | peer_sid, &ad); | ||
| 4020 | if (err) | ||
| 4021 | return err; | ||
| 4022 | err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, | ||
| 4023 | PEER__RECV, &ad); | ||
| 4024 | } | ||
| 4025 | |||
| 4026 | if (selinux_secmark_enabled()) { | ||
| 4027 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, | ||
| 4028 | PACKET__RECV, &ad); | ||
| 4029 | if (err) | ||
| 4030 | return err; | ||
| 4031 | } | ||
| 3946 | 4032 | ||
| 3947 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad); | ||
| 3948 | out: | ||
| 3949 | return err; | 4033 | return err; |
| 3950 | } | 4034 | } |
| 3951 | 4035 | ||
| @@ -3996,18 +4080,25 @@ out: | |||
| 3996 | static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) | 4080 | static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) |
| 3997 | { | 4081 | { |
| 3998 | u32 peer_secid = SECSID_NULL; | 4082 | u32 peer_secid = SECSID_NULL; |
| 3999 | int err = 0; | 4083 | u16 family; |
| 4084 | |||
| 4085 | if (sock) | ||
| 4086 | family = sock->sk->sk_family; | ||
| 4087 | else if (skb && skb->sk) | ||
| 4088 | family = skb->sk->sk_family; | ||
| 4089 | else | ||
| 4090 | goto out; | ||
| 4000 | 4091 | ||
| 4001 | if (sock && sock->sk->sk_family == PF_UNIX) | 4092 | if (sock && family == PF_UNIX) |
| 4002 | selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid); | 4093 | selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid); |
| 4003 | else if (skb) | 4094 | else if (skb) |
| 4004 | selinux_skb_extlbl_sid(skb, &peer_secid); | 4095 | selinux_skb_peerlbl_sid(skb, family, &peer_secid); |
| 4005 | 4096 | ||
| 4006 | if (peer_secid == SECSID_NULL) | 4097 | out: |
| 4007 | err = -EINVAL; | ||
| 4008 | *secid = peer_secid; | 4098 | *secid = peer_secid; |
| 4009 | 4099 | if (peer_secid == SECSID_NULL) | |
| 4010 | return err; | 4100 | return -EINVAL; |
| 4101 | return 0; | ||
| 4011 | } | 4102 | } |
| 4012 | 4103 | ||
| 4013 | static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority) | 4104 | static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority) |
| @@ -4027,6 +4118,7 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk) | |||
| 4027 | 4118 | ||
| 4028 | newssec->sid = ssec->sid; | 4119 | newssec->sid = ssec->sid; |
| 4029 | newssec->peer_sid = ssec->peer_sid; | 4120 | newssec->peer_sid = ssec->peer_sid; |
| 4121 | newssec->sclass = ssec->sclass; | ||
| 4030 | 4122 | ||
| 4031 | selinux_netlbl_sk_security_clone(ssec, newssec); | 4123 | selinux_netlbl_sk_security_clone(ssec, newssec); |
| 4032 | } | 4124 | } |
| @@ -4050,6 +4142,7 @@ static void selinux_sock_graft(struct sock* sk, struct socket *parent) | |||
| 4050 | if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 || | 4142 | if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 || |
| 4051 | sk->sk_family == PF_UNIX) | 4143 | sk->sk_family == PF_UNIX) |
| 4052 | isec->sid = sksec->sid; | 4144 | isec->sid = sksec->sid; |
| 4145 | sksec->sclass = isec->sclass; | ||
| 4053 | 4146 | ||
| 4054 | selinux_netlbl_sock_graft(sk, parent); | 4147 | selinux_netlbl_sock_graft(sk, parent); |
| 4055 | } | 4148 | } |
| @@ -4062,7 +4155,9 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
| 4062 | u32 newsid; | 4155 | u32 newsid; |
| 4063 | u32 peersid; | 4156 | u32 peersid; |
| 4064 | 4157 | ||
| 4065 | selinux_skb_extlbl_sid(skb, &peersid); | 4158 | err = selinux_skb_peerlbl_sid(skb, sk->sk_family, &peersid); |
| 4159 | if (err) | ||
| 4160 | return err; | ||
| 4066 | if (peersid == SECSID_NULL) { | 4161 | if (peersid == SECSID_NULL) { |
| 4067 | req->secid = sksec->sid; | 4162 | req->secid = sksec->sid; |
| 4068 | req->peer_secid = SECSID_NULL; | 4163 | req->peer_secid = SECSID_NULL; |
| @@ -4100,7 +4195,7 @@ static void selinux_inet_conn_established(struct sock *sk, | |||
| 4100 | { | 4195 | { |
| 4101 | struct sk_security_struct *sksec = sk->sk_security; | 4196 | struct sk_security_struct *sksec = sk->sk_security; |
| 4102 | 4197 | ||
| 4103 | selinux_skb_extlbl_sid(skb, &sksec->peer_sid); | 4198 | selinux_skb_peerlbl_sid(skb, sk->sk_family, &sksec->peer_sid); |
| 4104 | } | 4199 | } |
| 4105 | 4200 | ||
| 4106 | static void selinux_req_classify_flow(const struct request_sock *req, | 4201 | static void selinux_req_classify_flow(const struct request_sock *req, |
| @@ -4147,149 +4242,260 @@ out: | |||
| 4147 | 4242 | ||
| 4148 | #ifdef CONFIG_NETFILTER | 4243 | #ifdef CONFIG_NETFILTER |
| 4149 | 4244 | ||
| 4150 | static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device *dev, | 4245 | static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, |
| 4151 | struct avc_audit_data *ad, | 4246 | u16 family) |
| 4152 | u16 family, char *addrp, int len) | ||
| 4153 | { | 4247 | { |
| 4154 | int err = 0; | 4248 | char *addrp; |
| 4155 | u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0; | 4249 | u32 peer_sid; |
| 4156 | struct socket *sock; | 4250 | struct avc_audit_data ad; |
| 4157 | struct inode *inode; | 4251 | u8 secmark_active; |
| 4158 | struct inode_security_struct *isec; | 4252 | u8 peerlbl_active; |
| 4159 | 4253 | ||
| 4160 | sock = sk->sk_socket; | 4254 | if (!selinux_policycap_netpeer) |
| 4161 | if (!sock) | 4255 | return NF_ACCEPT; |
| 4162 | goto out; | ||
| 4163 | 4256 | ||
| 4164 | inode = SOCK_INODE(sock); | 4257 | secmark_active = selinux_secmark_enabled(); |
| 4165 | if (!inode) | 4258 | peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); |
| 4166 | goto out; | 4259 | if (!secmark_active && !peerlbl_active) |
| 4260 | return NF_ACCEPT; | ||
| 4167 | 4261 | ||
| 4168 | isec = inode->i_security; | 4262 | AVC_AUDIT_DATA_INIT(&ad, NET); |
| 4169 | 4263 | ad.u.net.netif = ifindex; | |
| 4170 | err = sel_netif_sids(dev, &if_sid, NULL); | 4264 | ad.u.net.family = family; |
| 4171 | if (err) | 4265 | if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) |
| 4172 | goto out; | 4266 | return NF_DROP; |
| 4267 | |||
| 4268 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) | ||
| 4269 | return NF_DROP; | ||
| 4270 | |||
| 4271 | if (peerlbl_active) | ||
| 4272 | if (selinux_inet_sys_rcv_skb(ifindex, addrp, family, | ||
| 4273 | peer_sid, &ad) != 0) | ||
| 4274 | return NF_DROP; | ||
| 4275 | |||
| 4276 | if (secmark_active) | ||
| 4277 | if (avc_has_perm(peer_sid, skb->secmark, | ||
| 4278 | SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) | ||
| 4279 | return NF_DROP; | ||
| 4280 | |||
| 4281 | return NF_ACCEPT; | ||
| 4282 | } | ||
| 4283 | |||
| 4284 | static unsigned int selinux_ipv4_forward(unsigned int hooknum, | ||
| 4285 | struct sk_buff *skb, | ||
| 4286 | const struct net_device *in, | ||
| 4287 | const struct net_device *out, | ||
| 4288 | int (*okfn)(struct sk_buff *)) | ||
| 4289 | { | ||
| 4290 | return selinux_ip_forward(skb, in->ifindex, PF_INET); | ||
| 4291 | } | ||
| 4173 | 4292 | ||
| 4174 | switch (isec->sclass) { | 4293 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
| 4294 | static unsigned int selinux_ipv6_forward(unsigned int hooknum, | ||
| 4295 | struct sk_buff *skb, | ||
| 4296 | const struct net_device *in, | ||
| 4297 | const struct net_device *out, | ||
| 4298 | int (*okfn)(struct sk_buff *)) | ||
| 4299 | { | ||
| 4300 | return selinux_ip_forward(skb, in->ifindex, PF_INET6); | ||
| 4301 | } | ||
| 4302 | #endif /* IPV6 */ | ||
| 4303 | |||
| 4304 | static int selinux_ip_postroute_iptables_compat(struct sock *sk, | ||
| 4305 | int ifindex, | ||
| 4306 | struct avc_audit_data *ad, | ||
| 4307 | u16 family, char *addrp) | ||
| 4308 | { | ||
| 4309 | int err; | ||
| 4310 | struct sk_security_struct *sksec = sk->sk_security; | ||
| 4311 | u16 sk_class; | ||
| 4312 | u32 netif_perm, node_perm, send_perm; | ||
| 4313 | u32 port_sid, node_sid, if_sid, sk_sid; | ||
| 4314 | |||
| 4315 | sk_sid = sksec->sid; | ||
| 4316 | sk_class = sksec->sclass; | ||
| 4317 | |||
| 4318 | switch (sk_class) { | ||
| 4175 | case SECCLASS_UDP_SOCKET: | 4319 | case SECCLASS_UDP_SOCKET: |
| 4176 | netif_perm = NETIF__UDP_SEND; | 4320 | netif_perm = NETIF__UDP_SEND; |
| 4177 | node_perm = NODE__UDP_SEND; | 4321 | node_perm = NODE__UDP_SEND; |
| 4178 | send_perm = UDP_SOCKET__SEND_MSG; | 4322 | send_perm = UDP_SOCKET__SEND_MSG; |
| 4179 | break; | 4323 | break; |
| 4180 | |||
| 4181 | case SECCLASS_TCP_SOCKET: | 4324 | case SECCLASS_TCP_SOCKET: |
| 4182 | netif_perm = NETIF__TCP_SEND; | 4325 | netif_perm = NETIF__TCP_SEND; |
| 4183 | node_perm = NODE__TCP_SEND; | 4326 | node_perm = NODE__TCP_SEND; |
| 4184 | send_perm = TCP_SOCKET__SEND_MSG; | 4327 | send_perm = TCP_SOCKET__SEND_MSG; |
| 4185 | break; | 4328 | break; |
| 4186 | |||
| 4187 | case SECCLASS_DCCP_SOCKET: | 4329 | case SECCLASS_DCCP_SOCKET: |
| 4188 | netif_perm = NETIF__DCCP_SEND; | 4330 | netif_perm = NETIF__DCCP_SEND; |
| 4189 | node_perm = NODE__DCCP_SEND; | 4331 | node_perm = NODE__DCCP_SEND; |
| 4190 | send_perm = DCCP_SOCKET__SEND_MSG; | 4332 | send_perm = DCCP_SOCKET__SEND_MSG; |
| 4191 | break; | 4333 | break; |
| 4192 | |||
| 4193 | default: | 4334 | default: |
| 4194 | netif_perm = NETIF__RAWIP_SEND; | 4335 | netif_perm = NETIF__RAWIP_SEND; |
| 4195 | node_perm = NODE__RAWIP_SEND; | 4336 | node_perm = NODE__RAWIP_SEND; |
| 4337 | send_perm = 0; | ||
| 4196 | break; | 4338 | break; |
| 4197 | } | 4339 | } |
| 4198 | 4340 | ||
| 4199 | err = avc_has_perm(isec->sid, if_sid, SECCLASS_NETIF, netif_perm, ad); | 4341 | err = sel_netif_sid(ifindex, &if_sid); |
| 4200 | if (err) | 4342 | if (err) |
| 4201 | goto out; | 4343 | return err; |
| 4344 | err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); | ||
| 4345 | return err; | ||
| 4202 | 4346 | ||
| 4203 | err = security_node_sid(family, addrp, len, &node_sid); | 4347 | err = sel_netnode_sid(addrp, family, &node_sid); |
| 4204 | if (err) | 4348 | if (err) |
| 4205 | goto out; | 4349 | return err; |
| 4206 | 4350 | err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad); | |
| 4207 | err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE, node_perm, ad); | ||
| 4208 | if (err) | 4351 | if (err) |
| 4209 | goto out; | 4352 | return err; |
| 4210 | 4353 | ||
| 4211 | if (send_perm) { | 4354 | if (send_perm != 0) |
| 4212 | u32 port_sid; | 4355 | return 0; |
| 4213 | |||
| 4214 | err = security_port_sid(sk->sk_family, | ||
| 4215 | sk->sk_type, | ||
| 4216 | sk->sk_protocol, | ||
| 4217 | ntohs(ad->u.net.dport), | ||
| 4218 | &port_sid); | ||
| 4219 | if (err) | ||
| 4220 | goto out; | ||
| 4221 | 4356 | ||
| 4222 | err = avc_has_perm(isec->sid, port_sid, isec->sclass, | 4357 | err = security_port_sid(sk->sk_family, sk->sk_type, |
| 4223 | send_perm, ad); | 4358 | sk->sk_protocol, ntohs(ad->u.net.dport), |
| 4359 | &port_sid); | ||
| 4360 | if (unlikely(err)) { | ||
| 4361 | printk(KERN_WARNING | ||
| 4362 | "SELinux: failure in" | ||
| 4363 | " selinux_ip_postroute_iptables_compat()," | ||
| 4364 | " network port label not found\n"); | ||
| 4365 | return err; | ||
| 4224 | } | 4366 | } |
| 4225 | out: | 4367 | return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad); |
| 4226 | return err; | ||
| 4227 | } | 4368 | } |
| 4228 | 4369 | ||
| 4229 | static unsigned int selinux_ip_postroute_last(unsigned int hooknum, | 4370 | static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, |
| 4230 | struct sk_buff *skb, | 4371 | int ifindex, |
| 4231 | const struct net_device *in, | 4372 | struct avc_audit_data *ad, |
| 4232 | const struct net_device *out, | 4373 | u16 family, |
| 4233 | int (*okfn)(struct sk_buff *), | 4374 | char *addrp, |
| 4234 | u16 family) | 4375 | u8 proto) |
| 4235 | { | 4376 | { |
| 4236 | char *addrp; | 4377 | struct sock *sk = skb->sk; |
| 4237 | int len, err = 0; | ||
| 4238 | struct sock *sk; | ||
| 4239 | struct avc_audit_data ad; | ||
| 4240 | struct net_device *dev = (struct net_device *)out; | ||
| 4241 | struct sk_security_struct *sksec; | 4378 | struct sk_security_struct *sksec; |
| 4242 | u8 proto; | ||
| 4243 | |||
| 4244 | sk = skb->sk; | ||
| 4245 | if (!sk) | ||
| 4246 | goto out; | ||
| 4247 | 4379 | ||
| 4380 | if (sk == NULL) | ||
| 4381 | return NF_ACCEPT; | ||
| 4248 | sksec = sk->sk_security; | 4382 | sksec = sk->sk_security; |
| 4249 | 4383 | ||
| 4250 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4384 | if (selinux_compat_net) { |
| 4251 | ad.u.net.netif = dev->name; | 4385 | if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex, |
| 4252 | ad.u.net.family = family; | 4386 | ad, family, addrp)) |
| 4387 | return NF_DROP; | ||
| 4388 | } else { | ||
| 4389 | if (avc_has_perm(sksec->sid, skb->secmark, | ||
| 4390 | SECCLASS_PACKET, PACKET__SEND, ad)) | ||
| 4391 | return NF_DROP; | ||
| 4392 | } | ||
| 4253 | 4393 | ||
| 4254 | err = selinux_parse_skb(skb, &ad, &addrp, &len, 0, &proto); | 4394 | if (selinux_policycap_netpeer) |
| 4255 | if (err) | 4395 | if (selinux_xfrm_postroute_last(sksec->sid, skb, ad, proto)) |
| 4256 | goto out; | 4396 | return NF_DROP; |
| 4257 | 4397 | ||
| 4258 | if (selinux_compat_net) | 4398 | return NF_ACCEPT; |
| 4259 | err = selinux_ip_postroute_last_compat(sk, dev, &ad, | 4399 | } |
| 4260 | family, addrp, len); | ||
| 4261 | else | ||
| 4262 | err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET, | ||
| 4263 | PACKET__SEND, &ad); | ||
| 4264 | 4400 | ||
| 4265 | if (err) | 4401 | static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, |
| 4266 | goto out; | 4402 | u16 family) |
| 4403 | { | ||
| 4404 | u32 secmark_perm; | ||
| 4405 | u32 peer_sid; | ||
| 4406 | struct sock *sk; | ||
| 4407 | struct avc_audit_data ad; | ||
| 4408 | char *addrp; | ||
| 4409 | u8 proto; | ||
| 4410 | u8 secmark_active; | ||
| 4411 | u8 peerlbl_active; | ||
| 4267 | 4412 | ||
| 4268 | err = selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto); | 4413 | AVC_AUDIT_DATA_INIT(&ad, NET); |
| 4269 | out: | 4414 | ad.u.net.netif = ifindex; |
| 4270 | return err ? NF_DROP : NF_ACCEPT; | 4415 | ad.u.net.family = family; |
| 4416 | if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) | ||
| 4417 | return NF_DROP; | ||
| 4418 | |||
| 4419 | /* If any sort of compatibility mode is enabled then handoff processing | ||
| 4420 | * to the selinux_ip_postroute_compat() function to deal with the | ||
| 4421 | * special handling. We do this in an attempt to keep this function | ||
| 4422 | * as fast and as clean as possible. */ | ||
| 4423 | if (selinux_compat_net || !selinux_policycap_netpeer) | ||
| 4424 | return selinux_ip_postroute_compat(skb, ifindex, &ad, | ||
| 4425 | family, addrp, proto); | ||
| 4426 | |||
| 4427 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec | ||
| 4428 | * packet transformation so allow the packet to pass without any checks | ||
| 4429 | * since we'll have another chance to perform access control checks | ||
| 4430 | * when the packet is on it's final way out. | ||
| 4431 | * NOTE: there appear to be some IPv6 multicast cases where skb->dst | ||
| 4432 | * is NULL, in this case go ahead and apply access control. */ | ||
| 4433 | if (skb->dst != NULL && skb->dst->xfrm != NULL) | ||
| 4434 | return NF_ACCEPT; | ||
| 4435 | |||
| 4436 | secmark_active = selinux_secmark_enabled(); | ||
| 4437 | peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); | ||
| 4438 | if (!secmark_active && !peerlbl_active) | ||
| 4439 | return NF_ACCEPT; | ||
| 4440 | |||
| 4441 | /* if the packet is locally generated (skb->sk != NULL) then use the | ||
| 4442 | * socket's label as the peer label, otherwise the packet is being | ||
| 4443 | * forwarded through this system and we need to fetch the peer label | ||
| 4444 | * directly from the packet */ | ||
| 4445 | sk = skb->sk; | ||
| 4446 | if (sk) { | ||
| 4447 | struct sk_security_struct *sksec = sk->sk_security; | ||
| 4448 | peer_sid = sksec->sid; | ||
| 4449 | secmark_perm = PACKET__SEND; | ||
| 4450 | } else { | ||
| 4451 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) | ||
| 4452 | return NF_DROP; | ||
| 4453 | secmark_perm = PACKET__FORWARD_OUT; | ||
| 4454 | } | ||
| 4455 | |||
| 4456 | if (secmark_active) | ||
| 4457 | if (avc_has_perm(peer_sid, skb->secmark, | ||
| 4458 | SECCLASS_PACKET, secmark_perm, &ad)) | ||
| 4459 | return NF_DROP; | ||
| 4460 | |||
| 4461 | if (peerlbl_active) { | ||
| 4462 | u32 if_sid; | ||
| 4463 | u32 node_sid; | ||
| 4464 | |||
| 4465 | if (sel_netif_sid(ifindex, &if_sid)) | ||
| 4466 | return NF_DROP; | ||
| 4467 | if (avc_has_perm(peer_sid, if_sid, | ||
| 4468 | SECCLASS_NETIF, NETIF__EGRESS, &ad)) | ||
| 4469 | return NF_DROP; | ||
| 4470 | |||
| 4471 | if (sel_netnode_sid(addrp, family, &node_sid)) | ||
| 4472 | return NF_DROP; | ||
| 4473 | if (avc_has_perm(peer_sid, node_sid, | ||
| 4474 | SECCLASS_NODE, NODE__SENDTO, &ad)) | ||
| 4475 | return NF_DROP; | ||
| 4476 | } | ||
| 4477 | |||
| 4478 | return NF_ACCEPT; | ||
| 4271 | } | 4479 | } |
| 4272 | 4480 | ||
| 4273 | static unsigned int selinux_ipv4_postroute_last(unsigned int hooknum, | 4481 | static unsigned int selinux_ipv4_postroute(unsigned int hooknum, |
| 4274 | struct sk_buff *skb, | 4482 | struct sk_buff *skb, |
| 4275 | const struct net_device *in, | 4483 | const struct net_device *in, |
| 4276 | const struct net_device *out, | 4484 | const struct net_device *out, |
| 4277 | int (*okfn)(struct sk_buff *)) | 4485 | int (*okfn)(struct sk_buff *)) |
| 4278 | { | 4486 | { |
| 4279 | return selinux_ip_postroute_last(hooknum, skb, in, out, okfn, PF_INET); | 4487 | return selinux_ip_postroute(skb, out->ifindex, PF_INET); |
| 4280 | } | 4488 | } |
| 4281 | 4489 | ||
| 4282 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 4490 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
| 4283 | 4491 | static unsigned int selinux_ipv6_postroute(unsigned int hooknum, | |
| 4284 | static unsigned int selinux_ipv6_postroute_last(unsigned int hooknum, | 4492 | struct sk_buff *skb, |
| 4285 | struct sk_buff *skb, | 4493 | const struct net_device *in, |
| 4286 | const struct net_device *in, | 4494 | const struct net_device *out, |
| 4287 | const struct net_device *out, | 4495 | int (*okfn)(struct sk_buff *)) |
| 4288 | int (*okfn)(struct sk_buff *)) | ||
| 4289 | { | 4496 | { |
| 4290 | return selinux_ip_postroute_last(hooknum, skb, in, out, okfn, PF_INET6); | 4497 | return selinux_ip_postroute(skb, out->ifindex, PF_INET6); |
| 4291 | } | 4498 | } |
| 4292 | |||
| 4293 | #endif /* IPV6 */ | 4499 | #endif /* IPV6 */ |
| 4294 | 4500 | ||
| 4295 | #endif /* CONFIG_NETFILTER */ | 4501 | #endif /* CONFIG_NETFILTER */ |
| @@ -5277,22 +5483,40 @@ security_initcall(selinux_init); | |||
| 5277 | 5483 | ||
| 5278 | #if defined(CONFIG_NETFILTER) | 5484 | #if defined(CONFIG_NETFILTER) |
| 5279 | 5485 | ||
| 5280 | static struct nf_hook_ops selinux_ipv4_op = { | 5486 | static struct nf_hook_ops selinux_ipv4_ops[] = { |
| 5281 | .hook = selinux_ipv4_postroute_last, | 5487 | { |
| 5282 | .owner = THIS_MODULE, | 5488 | .hook = selinux_ipv4_postroute, |
| 5283 | .pf = PF_INET, | 5489 | .owner = THIS_MODULE, |
| 5284 | .hooknum = NF_INET_POST_ROUTING, | 5490 | .pf = PF_INET, |
| 5285 | .priority = NF_IP_PRI_SELINUX_LAST, | 5491 | .hooknum = NF_INET_POST_ROUTING, |
| 5492 | .priority = NF_IP_PRI_SELINUX_LAST, | ||
| 5493 | }, | ||
| 5494 | { | ||
| 5495 | .hook = selinux_ipv4_forward, | ||
| 5496 | .owner = THIS_MODULE, | ||
| 5497 | .pf = PF_INET, | ||
| 5498 | .hooknum = NF_INET_FORWARD, | ||
| 5499 | .priority = NF_IP_PRI_SELINUX_FIRST, | ||
| 5500 | } | ||
| 5286 | }; | 5501 | }; |
| 5287 | 5502 | ||
| 5288 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 5503 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
| 5289 | 5504 | ||
| 5290 | static struct nf_hook_ops selinux_ipv6_op = { | 5505 | static struct nf_hook_ops selinux_ipv6_ops[] = { |
| 5291 | .hook = selinux_ipv6_postroute_last, | 5506 | { |
| 5292 | .owner = THIS_MODULE, | 5507 | .hook = selinux_ipv6_postroute, |
| 5293 | .pf = PF_INET6, | 5508 | .owner = THIS_MODULE, |
| 5294 | .hooknum = NF_INET_POST_ROUTING, | 5509 | .pf = PF_INET6, |
| 5295 | .priority = NF_IP6_PRI_SELINUX_LAST, | 5510 | .hooknum = NF_INET_POST_ROUTING, |
| 5511 | .priority = NF_IP6_PRI_SELINUX_LAST, | ||
| 5512 | }, | ||
| 5513 | { | ||
| 5514 | .hook = selinux_ipv6_forward, | ||
| 5515 | .owner = THIS_MODULE, | ||
| 5516 | .pf = PF_INET6, | ||
| 5517 | .hooknum = NF_INET_FORWARD, | ||
| 5518 | .priority = NF_IP6_PRI_SELINUX_FIRST, | ||
| 5519 | } | ||
| 5296 | }; | 5520 | }; |
| 5297 | 5521 | ||
| 5298 | #endif /* IPV6 */ | 5522 | #endif /* IPV6 */ |
| @@ -5300,22 +5524,27 @@ static struct nf_hook_ops selinux_ipv6_op = { | |||
| 5300 | static int __init selinux_nf_ip_init(void) | 5524 | static int __init selinux_nf_ip_init(void) |
| 5301 | { | 5525 | { |
| 5302 | int err = 0; | 5526 | int err = 0; |
| 5527 | u32 iter; | ||
| 5303 | 5528 | ||
| 5304 | if (!selinux_enabled) | 5529 | if (!selinux_enabled) |
| 5305 | goto out; | 5530 | goto out; |
| 5306 | 5531 | ||
| 5307 | printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n"); | 5532 | printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n"); |
| 5308 | 5533 | ||
| 5309 | err = nf_register_hook(&selinux_ipv4_op); | 5534 | for (iter = 0; iter < ARRAY_SIZE(selinux_ipv4_ops); iter++) { |
| 5310 | if (err) | 5535 | err = nf_register_hook(&selinux_ipv4_ops[iter]); |
| 5311 | panic("SELinux: nf_register_hook for IPv4: error %d\n", err); | 5536 | if (err) |
| 5537 | panic("SELinux: nf_register_hook for IPv4: error %d\n", | ||
| 5538 | err); | ||
| 5539 | } | ||
| 5312 | 5540 | ||
| 5313 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 5541 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
| 5314 | 5542 | for (iter = 0; iter < ARRAY_SIZE(selinux_ipv6_ops); iter++) { | |
| 5315 | err = nf_register_hook(&selinux_ipv6_op); | 5543 | err = nf_register_hook(&selinux_ipv6_ops[iter]); |
| 5316 | if (err) | 5544 | if (err) |
| 5317 | panic("SELinux: nf_register_hook for IPv6: error %d\n", err); | 5545 | panic("SELinux: nf_register_hook for IPv6: error %d\n", |
| 5318 | 5546 | err); | |
| 5547 | } | ||
| 5319 | #endif /* IPV6 */ | 5548 | #endif /* IPV6 */ |
| 5320 | 5549 | ||
| 5321 | out: | 5550 | out: |
| @@ -5327,11 +5556,15 @@ __initcall(selinux_nf_ip_init); | |||
| 5327 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE | 5556 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE |
| 5328 | static void selinux_nf_ip_exit(void) | 5557 | static void selinux_nf_ip_exit(void) |
| 5329 | { | 5558 | { |
| 5559 | u32 iter; | ||
| 5560 | |||
| 5330 | printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n"); | 5561 | printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n"); |
| 5331 | 5562 | ||
| 5332 | nf_unregister_hook(&selinux_ipv4_op); | 5563 | for (iter = 0; iter < ARRAY_SIZE(selinux_ipv4_ops); iter++) |
| 5564 | nf_unregister_hook(&selinux_ipv4_ops[iter]); | ||
| 5333 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 5565 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
| 5334 | nf_unregister_hook(&selinux_ipv6_op); | 5566 | for (iter = 0; iter < ARRAY_SIZE(selinux_ipv6_ops); iter++) |
| 5567 | nf_unregister_hook(&selinux_ipv6_ops[iter]); | ||
| 5335 | #endif /* IPV6 */ | 5568 | #endif /* IPV6 */ |
| 5336 | } | 5569 | } |
| 5337 | #endif | 5570 | #endif |
