diff options
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 64d414efb40..be6de0b8734 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 |