diff options
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r-- | security/selinux/hooks.c | 204 |
1 files changed, 112 insertions, 92 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4bca0af4f2af..bfe9a05db3a2 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -50,6 +50,7 @@ | |||
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> | ||
53 | #include <asm/uaccess.h> | 54 | #include <asm/uaccess.h> |
54 | #include <asm/ioctls.h> | 55 | #include <asm/ioctls.h> |
55 | #include <linux/bitops.h> | 56 | #include <linux/bitops.h> |
@@ -3426,36 +3427,39 @@ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, | |||
3426 | } | 3427 | } |
3427 | 3428 | ||
3428 | /** | 3429 | /** |
3429 | * selinux_skb_extlbl_sid - Determine the external label of a packet | 3430 | * selinux_skb_peerlbl_sid - Determine the peer label of a packet |
3430 | * @skb: the packet | 3431 | * @skb: the packet |
3431 | * @family: protocol family | 3432 | * @family: protocol family |
3432 | * @sid: the packet's SID | 3433 | * @sid: the packet's peer label SID |
3433 | * | 3434 | * |
3434 | * Description: | 3435 | * Description: |
3435 | * Check the various different forms of external packet labeling and determine | 3436 | * 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 | 3437 | * 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 | 3438 | * the security server function security_net_peersid_cmp(). The function |
3438 | * present then the SELinux type information is taken from the labeled IPsec | 3439 | * 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 | 3440 | * 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 | 3441 | * peer labels. |
3441 | * selinux_netlbl_skbuff_getsid(). | ||
3442 | * | 3442 | * |
3443 | */ | 3443 | */ |
3444 | static void selinux_skb_extlbl_sid(struct sk_buff *skb, | 3444 | static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid) |
3445 | u16 family, | ||
3446 | u32 *sid) | ||
3447 | { | 3445 | { |
3448 | u32 xfrm_sid; | 3446 | u32 xfrm_sid; |
3449 | u32 nlbl_sid; | 3447 | u32 nlbl_sid; |
3448 | u32 nlbl_type; | ||
3450 | 3449 | ||
3451 | selinux_skb_xfrm_sid(skb, &xfrm_sid); | 3450 | selinux_skb_xfrm_sid(skb, &xfrm_sid); |
3452 | if (selinux_netlbl_skbuff_getsid(skb, | 3451 | selinux_netlbl_skbuff_getsid(skb, |
3453 | family, | 3452 | family, |
3454 | (xfrm_sid == SECSID_NULL ? | 3453 | SECINITSID_NETMSG, |
3455 | SECINITSID_NETMSG : xfrm_sid), | 3454 | &nlbl_type, |
3456 | &nlbl_sid) != 0) | 3455 | &nlbl_sid); |
3457 | nlbl_sid = SECSID_NULL; | 3456 | |
3458 | *sid = (nlbl_sid == SECSID_NULL ? xfrm_sid : nlbl_sid); | 3457 | if (security_net_peersid_resolve(nlbl_sid, nlbl_type, |
3458 | xfrm_sid, | ||
3459 | sid) != 0) | ||
3460 | return -EACCES; | ||
3461 | |||
3462 | return 0; | ||
3459 | } | 3463 | } |
3460 | 3464 | ||
3461 | /* socket security operations */ | 3465 | /* socket security operations */ |
@@ -3521,6 +3525,7 @@ static int selinux_socket_post_create(struct socket *sock, int family, | |||
3521 | if (sock->sk) { | 3525 | if (sock->sk) { |
3522 | sksec = sock->sk->sk_security; | 3526 | sksec = sock->sk->sk_security; |
3523 | sksec->sid = isec->sid; | 3527 | sksec->sid = isec->sid; |
3528 | sksec->sclass = isec->sclass; | ||
3524 | err = selinux_netlbl_socket_post_create(sock); | 3529 | err = selinux_netlbl_socket_post_create(sock); |
3525 | } | 3530 | } |
3526 | 3531 | ||
@@ -3824,104 +3829,114 @@ static int selinux_socket_unix_may_send(struct socket *sock, | |||
3824 | return 0; | 3829 | return 0; |
3825 | } | 3830 | } |
3826 | 3831 | ||
3827 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | 3832 | static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk, |
3828 | struct avc_audit_data *ad, | 3833 | struct sk_buff *skb, |
3829 | u16 family, char *addrp) | 3834 | struct avc_audit_data *ad, |
3835 | u16 family, | ||
3836 | char *addrp) | ||
3830 | { | 3837 | { |
3831 | int err = 0; | 3838 | int err; |
3832 | u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0; | 3839 | struct sk_security_struct *sksec = sk->sk_security; |
3833 | struct socket *sock; | 3840 | u16 sk_class; |
3834 | u16 sock_class = 0; | 3841 | u32 netif_perm, node_perm, recv_perm; |
3835 | u32 sock_sid = 0; | 3842 | u32 port_sid, node_sid, if_sid, sk_sid; |
3836 | |||
3837 | read_lock_bh(&sk->sk_callback_lock); | ||
3838 | sock = sk->sk_socket; | ||
3839 | if (sock) { | ||
3840 | struct inode *inode; | ||
3841 | inode = SOCK_INODE(sock); | ||
3842 | if (inode) { | ||
3843 | struct inode_security_struct *isec; | ||
3844 | isec = inode->i_security; | ||
3845 | sock_sid = isec->sid; | ||
3846 | sock_class = isec->sclass; | ||
3847 | } | ||
3848 | } | ||
3849 | read_unlock_bh(&sk->sk_callback_lock); | ||
3850 | if (!sock_sid) | ||
3851 | goto out; | ||
3852 | |||
3853 | if (!skb->dev) | ||
3854 | goto out; | ||
3855 | 3843 | ||
3856 | err = sel_netif_sid(skb->iif, &if_sid); | 3844 | sk_sid = sksec->sid; |
3857 | if (err) | 3845 | sk_class = sksec->sclass; |
3858 | goto out; | ||
3859 | 3846 | ||
3860 | switch (sock_class) { | 3847 | switch (sk_class) { |
3861 | case SECCLASS_UDP_SOCKET: | 3848 | case SECCLASS_UDP_SOCKET: |
3862 | netif_perm = NETIF__UDP_RECV; | 3849 | netif_perm = NETIF__UDP_RECV; |
3863 | node_perm = NODE__UDP_RECV; | 3850 | node_perm = NODE__UDP_RECV; |
3864 | recv_perm = UDP_SOCKET__RECV_MSG; | 3851 | recv_perm = UDP_SOCKET__RECV_MSG; |
3865 | break; | 3852 | break; |
3866 | |||
3867 | case SECCLASS_TCP_SOCKET: | 3853 | case SECCLASS_TCP_SOCKET: |
3868 | netif_perm = NETIF__TCP_RECV; | 3854 | netif_perm = NETIF__TCP_RECV; |
3869 | node_perm = NODE__TCP_RECV; | 3855 | node_perm = NODE__TCP_RECV; |
3870 | recv_perm = TCP_SOCKET__RECV_MSG; | 3856 | recv_perm = TCP_SOCKET__RECV_MSG; |
3871 | break; | 3857 | break; |
3872 | |||
3873 | case SECCLASS_DCCP_SOCKET: | 3858 | case SECCLASS_DCCP_SOCKET: |
3874 | netif_perm = NETIF__DCCP_RECV; | 3859 | netif_perm = NETIF__DCCP_RECV; |
3875 | node_perm = NODE__DCCP_RECV; | 3860 | node_perm = NODE__DCCP_RECV; |
3876 | recv_perm = DCCP_SOCKET__RECV_MSG; | 3861 | recv_perm = DCCP_SOCKET__RECV_MSG; |
3877 | break; | 3862 | break; |
3878 | |||
3879 | default: | 3863 | default: |
3880 | netif_perm = NETIF__RAWIP_RECV; | 3864 | netif_perm = NETIF__RAWIP_RECV; |
3881 | node_perm = NODE__RAWIP_RECV; | 3865 | node_perm = NODE__RAWIP_RECV; |
3866 | recv_perm = 0; | ||
3882 | break; | 3867 | break; |
3883 | } | 3868 | } |
3884 | 3869 | ||
3885 | err = avc_has_perm(sock_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); | 3870 | err = sel_netif_sid(skb->iif, &if_sid); |
3886 | if (err) | 3871 | if (err) |
3887 | goto out; | 3872 | return err; |
3873 | err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); | ||
3874 | if (err) | ||
3875 | return err; | ||
3888 | 3876 | ||
3889 | err = sel_netnode_sid(addrp, family, &node_sid); | 3877 | err = sel_netnode_sid(addrp, family, &node_sid); |
3890 | if (err) | 3878 | if (err) |
3891 | goto out; | 3879 | return err; |
3892 | 3880 | err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad); | |
3893 | err = avc_has_perm(sock_sid, node_sid, SECCLASS_NODE, node_perm, ad); | ||
3894 | if (err) | 3881 | if (err) |
3895 | goto out; | 3882 | return err; |
3896 | 3883 | ||
3897 | if (recv_perm) { | 3884 | if (!recv_perm) |
3898 | u32 port_sid; | 3885 | return 0; |
3886 | err = security_port_sid(sk->sk_family, sk->sk_type, | ||
3887 | sk->sk_protocol, ntohs(ad->u.net.sport), | ||
3888 | &port_sid); | ||
3889 | if (err) | ||
3890 | return err; | ||
3891 | return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad); | ||
3892 | } | ||
3899 | 3893 | ||
3900 | err = security_port_sid(sk->sk_family, sk->sk_type, | 3894 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, |
3901 | sk->sk_protocol, ntohs(ad->u.net.sport), | 3895 | struct avc_audit_data *ad, |
3902 | &port_sid); | 3896 | u16 family, char *addrp) |
3903 | if (err) | 3897 | { |
3904 | goto out; | 3898 | int err; |
3899 | struct sk_security_struct *sksec = sk->sk_security; | ||
3900 | u32 peer_sid; | ||
3901 | u32 sk_sid = sksec->sid; | ||
3902 | |||
3903 | if (selinux_compat_net) | ||
3904 | err = selinux_sock_rcv_skb_iptables_compat(sk, skb, ad, | ||
3905 | family, addrp); | ||
3906 | else | ||
3907 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, | ||
3908 | PACKET__RECV, ad); | ||
3909 | if (err) | ||
3910 | return err; | ||
3905 | 3911 | ||
3906 | err = avc_has_perm(sock_sid, port_sid, | 3912 | if (selinux_policycap_netpeer) { |
3907 | sock_class, recv_perm, ad); | 3913 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); |
3914 | if (err) | ||
3915 | return err; | ||
3916 | err = avc_has_perm(sk_sid, peer_sid, | ||
3917 | SECCLASS_PEER, PEER__RECV, ad); | ||
3918 | } else { | ||
3919 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, ad); | ||
3920 | if (err) | ||
3921 | return err; | ||
3922 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, ad); | ||
3908 | } | 3923 | } |
3909 | 3924 | ||
3910 | out: | ||
3911 | return err; | 3925 | return err; |
3912 | } | 3926 | } |
3913 | 3927 | ||
3914 | static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | 3928 | static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) |
3915 | { | 3929 | { |
3916 | u16 family; | 3930 | int err; |
3917 | char *addrp; | ||
3918 | int err = 0; | ||
3919 | struct avc_audit_data ad; | ||
3920 | struct sk_security_struct *sksec = sk->sk_security; | 3931 | struct sk_security_struct *sksec = sk->sk_security; |
3932 | u16 family = sk->sk_family; | ||
3933 | u32 sk_sid = sksec->sid; | ||
3934 | u32 peer_sid; | ||
3935 | struct avc_audit_data ad; | ||
3936 | char *addrp; | ||
3921 | 3937 | ||
3922 | family = sk->sk_family; | ||
3923 | if (family != PF_INET && family != PF_INET6) | 3938 | if (family != PF_INET && family != PF_INET6) |
3924 | goto out; | 3939 | return 0; |
3925 | 3940 | ||
3926 | /* Handle mapped IPv4 packets arriving via IPv6 sockets */ | 3941 | /* Handle mapped IPv4 packets arriving via IPv6 sockets */ |
3927 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | 3942 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) |
@@ -3930,26 +3945,27 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
3930 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3945 | AVC_AUDIT_DATA_INIT(&ad, NET); |
3931 | ad.u.net.netif = skb->iif; | 3946 | ad.u.net.netif = skb->iif; |
3932 | ad.u.net.family = family; | 3947 | ad.u.net.family = family; |
3933 | |||
3934 | err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); | 3948 | err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); |
3935 | if (err) | 3949 | if (err) |
3936 | goto out; | 3950 | return err; |
3937 | 3951 | ||
3938 | if (selinux_compat_net) | 3952 | /* If any sort of compatibility mode is enabled then handoff processing |
3939 | err = selinux_sock_rcv_skb_compat(sk, skb, &ad, family, addrp); | 3953 | * to the selinux_sock_rcv_skb_compat() function to deal with the |
3940 | else | 3954 | * special handling. We do this in an attempt to keep this function |
3941 | err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET, | 3955 | * as fast and as clean as possible. */ |
3942 | PACKET__RECV, &ad); | 3956 | if (selinux_compat_net || !selinux_policycap_netpeer) |
3943 | if (err) | 3957 | return selinux_sock_rcv_skb_compat(sk, skb, &ad, |
3944 | goto out; | 3958 | family, addrp); |
3945 | 3959 | ||
3946 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad); | 3960 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, |
3961 | PACKET__RECV, &ad); | ||
3947 | if (err) | 3962 | if (err) |
3948 | goto out; | 3963 | return err; |
3949 | 3964 | ||
3950 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad); | 3965 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); |
3951 | out: | 3966 | if (err) |
3952 | return err; | 3967 | return err; |
3968 | return avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, PEER__RECV, &ad); | ||
3953 | } | 3969 | } |
3954 | 3970 | ||
3955 | static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval, | 3971 | static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval, |
@@ -4011,7 +4027,7 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff * | |||
4011 | if (sock && family == PF_UNIX) | 4027 | if (sock && family == PF_UNIX) |
4012 | selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid); | 4028 | selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid); |
4013 | else if (skb) | 4029 | else if (skb) |
4014 | selinux_skb_extlbl_sid(skb, family, &peer_secid); | 4030 | selinux_skb_peerlbl_sid(skb, family, &peer_secid); |
4015 | 4031 | ||
4016 | out: | 4032 | out: |
4017 | *secid = peer_secid; | 4033 | *secid = peer_secid; |
@@ -4037,6 +4053,7 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk) | |||
4037 | 4053 | ||
4038 | newssec->sid = ssec->sid; | 4054 | newssec->sid = ssec->sid; |
4039 | newssec->peer_sid = ssec->peer_sid; | 4055 | newssec->peer_sid = ssec->peer_sid; |
4056 | newssec->sclass = ssec->sclass; | ||
4040 | 4057 | ||
4041 | selinux_netlbl_sk_security_clone(ssec, newssec); | 4058 | selinux_netlbl_sk_security_clone(ssec, newssec); |
4042 | } | 4059 | } |
@@ -4060,6 +4077,7 @@ static void selinux_sock_graft(struct sock* sk, struct socket *parent) | |||
4060 | if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 || | 4077 | if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 || |
4061 | sk->sk_family == PF_UNIX) | 4078 | sk->sk_family == PF_UNIX) |
4062 | isec->sid = sksec->sid; | 4079 | isec->sid = sksec->sid; |
4080 | sksec->sclass = isec->sclass; | ||
4063 | 4081 | ||
4064 | selinux_netlbl_sock_graft(sk, parent); | 4082 | selinux_netlbl_sock_graft(sk, parent); |
4065 | } | 4083 | } |
@@ -4072,7 +4090,9 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
4072 | u32 newsid; | 4090 | u32 newsid; |
4073 | u32 peersid; | 4091 | u32 peersid; |
4074 | 4092 | ||
4075 | selinux_skb_extlbl_sid(skb, sk->sk_family, &peersid); | 4093 | err = selinux_skb_peerlbl_sid(skb, sk->sk_family, &peersid); |
4094 | if (err) | ||
4095 | return err; | ||
4076 | if (peersid == SECSID_NULL) { | 4096 | if (peersid == SECSID_NULL) { |
4077 | req->secid = sksec->sid; | 4097 | req->secid = sksec->sid; |
4078 | req->peer_secid = SECSID_NULL; | 4098 | req->peer_secid = SECSID_NULL; |
@@ -4110,7 +4130,7 @@ static void selinux_inet_conn_established(struct sock *sk, | |||
4110 | { | 4130 | { |
4111 | struct sk_security_struct *sksec = sk->sk_security; | 4131 | struct sk_security_struct *sksec = sk->sk_security; |
4112 | 4132 | ||
4113 | selinux_skb_extlbl_sid(skb, sk->sk_family, &sksec->peer_sid); | 4133 | selinux_skb_peerlbl_sid(skb, sk->sk_family, &sksec->peer_sid); |
4114 | } | 4134 | } |
4115 | 4135 | ||
4116 | static void selinux_req_classify_flow(const struct request_sock *req, | 4136 | static void selinux_req_classify_flow(const struct request_sock *req, |