aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/hooks.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r--security/selinux/hooks.c204
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 */
3444static void selinux_skb_extlbl_sid(struct sk_buff *skb, 3444static 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
3827static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, 3832static 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, 3894static 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
3910out:
3911 return err; 3925 return err;
3912} 3926}
3913 3927
3914static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) 3928static 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);
3951out: 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
3955static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval, 3971static 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
4016out: 4032out:
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
4116static void selinux_req_classify_flow(const struct request_sock *req, 4136static void selinux_req_classify_flow(const struct request_sock *req,